You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

385 lines
9.2 KiB

2 years ago
  1. import 'dart:collection';
  2. import 'dart:math';
  3. import 'package:collection/collection.dart';
  4. import 'package:flutter/foundation.dart';
  5. import 'package:tuple/tuple.dart';
  6. class Node {
  7. final List<List<int>> board;
  8. final Node? previous;
  9. final int heuristic;
  10. final int depth;
  11. Node({
  12. required this.board,
  13. required this.previous,
  14. required this.heuristic,
  15. required this.depth,
  16. });
  17. Node getNodeState() {
  18. return Node(
  19. board: board,
  20. previous: previous,
  21. heuristic: heuristic,
  22. depth: depth,
  23. );
  24. }
  25. List<Node> generateChildren({required int size}) {
  26. late int x;
  27. late int y;
  28. for (int i = 0; i < size; i++) {
  29. for (int j = 0; j < size; j++) {
  30. if (board[i][j] == 0) {
  31. x = i;
  32. y = j;
  33. }
  34. }
  35. }
  36. // print('x: $x, y: $y');
  37. List<List<int>> valList = [
  38. [x, y - 1],
  39. [x, y + 1],
  40. [x - 1, y],
  41. [x + 1, y]
  42. ];
  43. List<Node> children = [];
  44. for (var child in valList) {
  45. if ((child[0] >= 0) && (child[0] < size) && (child[1] >= 0) && (child[1] < size)) {
  46. List<List<int>> childBoard = [];
  47. // ERROR (FIXED): This board is getting modified
  48. // print('------------------------------');
  49. // print('BOARD: $board');
  50. // print('------------------------------');
  51. for (var row in board) {
  52. childBoard.add([...row]);
  53. }
  54. // print('***********************************');
  55. // print('CHILD: $childBoard');
  56. // print('***********************************');
  57. childBoard[x][y] = childBoard[child[0]][child[1]];
  58. childBoard[child[0]][child[1]] = 0;
  59. final solverClient = PuzzleSolverClient(size: size);
  60. final childNode = Node(
  61. board: childBoard,
  62. previous: this,
  63. heuristic: solverClient.nodeManhattan(childBoard),
  64. depth: depth + 1,
  65. );
  66. children.add(childNode);
  67. }
  68. }
  69. return children;
  70. }
  71. }
  72. class PuzzleSolverClient {
  73. int size;
  74. PuzzleSolverClient({this.size = 3});
  75. set setSize(int newSize) => size = newSize;
  76. List<List<int>> createRandomBoard({bool solvable = true}) {
  77. List<List<int>> board = [];
  78. for (int i = 0; i < size; i++) {
  79. List<int> temp = [];
  80. for (int j = 0; j < size; j++) {
  81. temp.add(0);
  82. }
  83. board.add(temp);
  84. }
  85. List<int> s = [];
  86. for (int i = 0; i < (size * size); i++) {
  87. s.add(i);
  88. }
  89. for (int i = 0; i < size; i++) {
  90. for (int j = 0; j < size; j++) {
  91. int item = s[Random().nextInt(s.length)];
  92. board[i][j] = item;
  93. s.remove(item);
  94. }
  95. }
  96. if (solvable) {
  97. if (!(isSolvable(board))) {
  98. if ((board[2][1] != 0) && (board[2][2] != 0)) {
  99. var temp = board[2][1];
  100. board[2][1] = board[2][2];
  101. board[2][2] = temp;
  102. } else {
  103. var temp = board[0][0];
  104. board[0][0] = board[0][1];
  105. board[0][1] = temp;
  106. }
  107. }
  108. }
  109. return board;
  110. }
  111. void plainPrint(List<List<int>> b) {
  112. for (var i in b) {
  113. for (var j in i) {
  114. print('$j ');
  115. }
  116. }
  117. }
  118. int nodeManhattan(List<List<int>> board) {
  119. int sum = 0;
  120. int n = board.length;
  121. for (int i = 0; i < size; i++) {
  122. for (int j = 0; j < size; j++) {
  123. int x = (board[i][j] - 1) ~/ n;
  124. int y = (board[i][j] - 1) % n;
  125. if (board[i][j] != 0) {
  126. sum += (x - i).abs() + (y - j).abs();
  127. }
  128. }
  129. }
  130. return sum;
  131. }
  132. int manhattan(List<List<int>> board, Set<int> goalNums) {
  133. int sum = 0;
  134. int count = 0;
  135. for (int i = 0; i < size; i++) {
  136. for (int j = 0; j < size; j++) {
  137. if (goalNums.contains(board[i][j])) {
  138. int x = (board[i][j] - 1) ~/ size;
  139. int y = ((board[i][j] - 1) % size).toInt();
  140. sum += (x - i).abs() + (y - j).abs();
  141. }
  142. }
  143. }
  144. return sum;
  145. }
  146. List<int> toTuple(List<List<int>> board) {
  147. List<int> lst = [];
  148. for (int i = 0; i < size; i++) {
  149. for (int j = 0; j < size; j++) {
  150. lst.add(board[i][j]);
  151. }
  152. }
  153. return lst;
  154. }
  155. bool isGoal(List<List<int>> board, Set<int> goalNums) {
  156. int count = 0;
  157. for (int i = 0; i < size; i++) {
  158. for (int j = 0; j < size; j++) {
  159. count += 1;
  160. if ((goalNums.contains(count)) && (board[i][j] != count)) {
  161. return false;
  162. }
  163. }
  164. }
  165. return true;
  166. }
  167. bool isSolvable(board) {
  168. int n = board.length;
  169. List<int> lst = [];
  170. bool blankOnEven = false;
  171. for (int i = 0; i < n; i++) {
  172. for (int j = 0; j < n; j++) {
  173. if (board[i][j] != 0) {
  174. lst.add(board[i][j]);
  175. } else {
  176. if (i % 2 == 0) {
  177. blankOnEven = true;
  178. }
  179. }
  180. }
  181. }
  182. int inversions = 0;
  183. for (int i = 0; i < lst.length; i++) {
  184. for (int j = i + 1; j < lst.length; j++) {
  185. if (lst[i] > lst[j]) {
  186. inversions += 1;
  187. }
  188. }
  189. }
  190. if (n % 2 == 1) {
  191. if (inversions % 2 == 1) {
  192. return false;
  193. } else {
  194. return true;
  195. }
  196. }
  197. if (((inversions % 2 == 0) && blankOnEven) || ((inversions % 2 == 1) && !blankOnEven)) {
  198. return false;
  199. }
  200. return true;
  201. }
  202. List<Set<int>> inOrderGoalStates(n) {
  203. List<Set<int>> goalStates = [];
  204. int c = 1;
  205. for (int i = 0; i < n; i++) {
  206. for (int j = i + 1; j < n; j++) {
  207. if ((i == (n - 1)) && (j == n - 1)) {
  208. break;
  209. }
  210. Set<int> set1 = {c};
  211. goalStates.add(set1);
  212. if ((i > 0) || (j > 0)) {
  213. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  214. }
  215. c += 1;
  216. }
  217. }
  218. return goalStates;
  219. }
  220. List<Set<int>> rowColGoalStates(n) {
  221. List<Set<int>> goalStates = [];
  222. for (int layer = 0; layer < n - 2; layer++) {
  223. for (int i = 0; i < n - layer; i++) {
  224. Set<int> set1 = {(n * layer) + i + 1};
  225. goalStates.add(set1);
  226. if (goalStates.length > 1) {
  227. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  228. }
  229. }
  230. for (int i = 0; i < n - layer - 1; i++) {
  231. Set<int> set1 = {(n + 1) + (i * n)};
  232. goalStates.add(set1);
  233. if (goalStates.length > 1) {
  234. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  235. }
  236. }
  237. }
  238. Set<int> set1 = {};
  239. for (int i = 1; i < n * n; i++) {
  240. set1.add(i);
  241. }
  242. goalStates.add(set1);
  243. return (goalStates);
  244. }
  245. List<int> convertTo1D(List<List<int>> board) {
  246. List<int> board1D = [];
  247. for (var row in board) {
  248. board1D.addAll(row);
  249. }
  250. return board1D;
  251. }
  252. List<List<int>> convertTo2D(List<int> board1D) {
  253. List<List<int>> chunks = [];
  254. int chunkSize = size;
  255. for (var i = 0; i < board1D.length; i += chunkSize) {
  256. chunks.add(board1D.sublist(i, i + chunkSize > board1D.length ? board1D.length : i + chunkSize));
  257. }
  258. return chunks;
  259. }
  260. List<List<int>>? runner(List<List<int>> board) {
  261. final queue = HeapPriorityQueue<Tuple2<int, Node>>((a, b) => a.item1.compareTo(b.item1));
  262. HashSet<List<int>> visited = HashSet<List<int>>();
  263. if (kDebugMode) {
  264. print('BOARD:');
  265. }
  266. for (var element in board) {
  267. if (kDebugMode) {
  268. print(element);
  269. }
  270. }
  271. List<Set<int>> goalStates = [];
  272. int count = 1;
  273. String flag = 'A_STAR';
  274. if (flag == 'A_STAR') {
  275. goalStates = rowColGoalStates(size);
  276. goalStates = [goalStates.last];
  277. } else if (flag == "HUMAN") {
  278. goalStates = rowColGoalStates(size);
  279. }
  280. int hScaleFactor = 3;
  281. int currGoal = 0;
  282. Node root = Node(
  283. board: board,
  284. previous: null,
  285. heuristic: manhattan(board, goalStates[currGoal]),
  286. depth: 0,
  287. );
  288. queue.add(Tuple2<int, Node>(root.depth + hScaleFactor * root.heuristic, root));
  289. while (queue.isNotEmpty) {
  290. count += 1;
  291. final node = queue.removeFirst().item2;
  292. if (isGoal(node.board, goalStates[currGoal])) {
  293. queue.clear();
  294. currGoal += 1;
  295. if (currGoal == goalStates.length) {
  296. Node? temp = node;
  297. List<List<List<int>>> boards = [];
  298. while (temp != null) {
  299. boards.add(temp.board);
  300. temp = temp.previous;
  301. }
  302. boards = boards.reversed.toList();
  303. List<List<int>> finalBoards = [];
  304. for (var i in boards) {
  305. finalBoards.add(convertTo1D(i));
  306. }
  307. return finalBoards;
  308. }
  309. root = Node(
  310. board: board,
  311. previous: null,
  312. heuristic: manhattan(board, goalStates[currGoal]),
  313. depth: 0,
  314. );
  315. queue.add(Tuple2(root.depth + hScaleFactor * root.heuristic, root));
  316. }
  317. var t = toTuple(node.board);
  318. visited.add(t);
  319. final children = node.generateChildren(size: size);
  320. for (Node child in children) {
  321. var tt = toTuple(child.board);
  322. bool isSetEqual = visited.any((value) {
  323. return value.equals(tt);
  324. });
  325. if (!isSetEqual) {
  326. queue.add(
  327. Tuple2(child.depth + hScaleFactor * manhattan(child.board, goalStates[currGoal]), child),
  328. );
  329. // print('${queue.first.item1}, ${queue.first.item2.board}');
  330. }
  331. }
  332. }
  333. return null;
  334. }
  335. }