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.

374 lines
9.0 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. int nodeManhattan(List<List<int>> board) {
  112. int sum = 0;
  113. int n = board.length;
  114. for (int i = 0; i < size; i++) {
  115. for (int j = 0; j < size; j++) {
  116. int x = (board[i][j] - 1) ~/ n;
  117. int y = (board[i][j] - 1) % n;
  118. if (board[i][j] != 0) {
  119. sum += (x - i).abs() + (y - j).abs();
  120. }
  121. }
  122. }
  123. return sum;
  124. }
  125. int manhattan(List<List<int>> board, Set<int> goalNums) {
  126. int sum = 0;
  127. for (int i = 0; i < size; i++) {
  128. for (int j = 0; j < size; j++) {
  129. if (goalNums.contains(board[i][j])) {
  130. int x = (board[i][j] - 1) ~/ size;
  131. int y = ((board[i][j] - 1) % size).toInt();
  132. sum += (x - i).abs() + (y - j).abs();
  133. }
  134. }
  135. }
  136. return sum;
  137. }
  138. List<int> toTuple(List<List<int>> board) {
  139. List<int> lst = [];
  140. for (int i = 0; i < size; i++) {
  141. for (int j = 0; j < size; j++) {
  142. lst.add(board[i][j]);
  143. }
  144. }
  145. return lst;
  146. }
  147. bool isGoal(List<List<int>> board, Set<int> goalNums) {
  148. int count = 0;
  149. for (int i = 0; i < size; i++) {
  150. for (int j = 0; j < size; j++) {
  151. count += 1;
  152. if ((goalNums.contains(count)) && (board[i][j] != count)) {
  153. return false;
  154. }
  155. }
  156. }
  157. return true;
  158. }
  159. bool isSolvable(board) {
  160. int n = board.length;
  161. List<int> lst = [];
  162. bool blankOnEven = false;
  163. for (int i = 0; i < n; i++) {
  164. for (int j = 0; j < n; j++) {
  165. if (board[i][j] != 0) {
  166. lst.add(board[i][j]);
  167. } else {
  168. if (i % 2 == 0) {
  169. blankOnEven = true;
  170. }
  171. }
  172. }
  173. }
  174. int inversions = 0;
  175. for (int i = 0; i < lst.length; i++) {
  176. for (int j = i + 1; j < lst.length; j++) {
  177. if (lst[i] > lst[j]) {
  178. inversions += 1;
  179. }
  180. }
  181. }
  182. if (n % 2 == 1) {
  183. if (inversions % 2 == 1) {
  184. return false;
  185. } else {
  186. return true;
  187. }
  188. }
  189. if (((inversions % 2 == 0) && blankOnEven) || ((inversions % 2 == 1) && !blankOnEven)) {
  190. return false;
  191. }
  192. return true;
  193. }
  194. List<Set<int>> inOrderGoalStates(n) {
  195. List<Set<int>> goalStates = [];
  196. int c = 1;
  197. for (int i = 0; i < n; i++) {
  198. for (int j = i + 1; j < n; j++) {
  199. if ((i == (n - 1)) && (j == n - 1)) {
  200. break;
  201. }
  202. Set<int> set1 = {c};
  203. goalStates.add(set1);
  204. if ((i > 0) || (j > 0)) {
  205. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  206. }
  207. c += 1;
  208. }
  209. }
  210. return goalStates;
  211. }
  212. List<Set<int>> rowColGoalStates(n) {
  213. List<Set<int>> goalStates = [];
  214. for (int layer = 0; layer < n - 2; layer++) {
  215. for (int i = 0; i < n - layer; i++) {
  216. Set<int> set1 = {(n * layer) + i + 1};
  217. goalStates.add(set1);
  218. if (goalStates.length > 1) {
  219. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  220. }
  221. }
  222. for (int i = 0; i < n - layer - 1; i++) {
  223. Set<int> set1 = {(n + 1) + (i * n)};
  224. goalStates.add(set1);
  225. if (goalStates.length > 1) {
  226. goalStates.last = (goalStates.last).union(goalStates[goalStates.length - 2]);
  227. }
  228. }
  229. }
  230. Set<int> set1 = {};
  231. for (int i = 1; i < n * n; i++) {
  232. set1.add(i);
  233. }
  234. goalStates.add(set1);
  235. return (goalStates);
  236. }
  237. List<int> convertTo1D(List<List<int>> board) {
  238. List<int> board1D = [];
  239. for (var row in board) {
  240. board1D.addAll(row);
  241. }
  242. return board1D;
  243. }
  244. List<List<int>> convertTo2D(List<int> board1D) {
  245. List<List<int>> chunks = [];
  246. int chunkSize = size;
  247. for (var i = 0; i < board1D.length; i += chunkSize) {
  248. chunks.add(board1D.sublist(i, i + chunkSize > board1D.length ? board1D.length : i + chunkSize));
  249. }
  250. return chunks;
  251. }
  252. List<List<int>>? runner(List<List<int>> board) {
  253. final queue = HeapPriorityQueue<Tuple2<int, Node>>((a, b) => a.item1.compareTo(b.item1));
  254. HashSet<List<int>> visited = HashSet<List<int>>();
  255. if (kDebugMode) {
  256. print('BOARD:');
  257. }
  258. for (var element in board) {
  259. if (kDebugMode) {
  260. print(element);
  261. }
  262. }
  263. List<Set<int>> goalStates = [];
  264. String flag = 'A_STAR';
  265. if (flag == 'A_STAR') {
  266. goalStates = rowColGoalStates(size);
  267. goalStates = [goalStates.last];
  268. } else if (flag == "HUMAN") {
  269. goalStates = rowColGoalStates(size);
  270. }
  271. int hScaleFactor = 3;
  272. int currGoal = 0;
  273. Node root = Node(
  274. board: board,
  275. previous: null,
  276. heuristic: manhattan(board, goalStates[currGoal]),
  277. depth: 0,
  278. );
  279. queue.add(Tuple2<int, Node>(root.depth + hScaleFactor * root.heuristic, root));
  280. while (queue.isNotEmpty) {
  281. final node = queue.removeFirst().item2;
  282. if (isGoal(node.board, goalStates[currGoal])) {
  283. queue.clear();
  284. currGoal += 1;
  285. if (currGoal == goalStates.length) {
  286. Node? temp = node;
  287. List<List<List<int>>> boards = [];
  288. while (temp != null) {
  289. boards.add(temp.board);
  290. temp = temp.previous;
  291. }
  292. boards = boards.reversed.toList();
  293. List<List<int>> finalBoards = [];
  294. for (var i in boards) {
  295. finalBoards.add(convertTo1D(i));
  296. }
  297. return finalBoards;
  298. }
  299. root = Node(
  300. board: board,
  301. previous: null,
  302. heuristic: manhattan(board, goalStates[currGoal]),
  303. depth: 0,
  304. );
  305. queue.add(Tuple2(root.depth + hScaleFactor * root.heuristic, root));
  306. }
  307. var t = toTuple(node.board);
  308. visited.add(t);
  309. final children = node.generateChildren(size: size);
  310. for (Node child in children) {
  311. var tt = toTuple(child.board);
  312. bool isSetEqual = visited.any((value) {
  313. return value.equals(tt);
  314. });
  315. if (!isSetEqual) {
  316. queue.add(
  317. Tuple2(child.depth + hScaleFactor * manhattan(child.board, goalStates[currGoal]), child),
  318. );
  319. // print('${queue.first.item1}, ${queue.first.item2.board}');
  320. }
  321. }
  322. }
  323. return null;
  324. }
  325. }