Advertisement
VladNitu

vladmiriteam

Feb 26th, 2024
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.77 KB | None | 0 0
  1. import static java.lang.System.out;
  2.  
  3. import java.util.*;
  4.  
  5. import agents.ArtificialAgent;
  6. import game.actions.EDirection;
  7. import game.actions.compact.*;
  8. import game.board.compact.BoardCompact;
  9. import game.board.compact.CTile;
  10.  
  11. /**
  12. * The simplest Tree-DFS agent.
  13. * @author Jimmy
  14. */
  15. public class MyAgent extends ArtificialAgent {
  16. class MyState {
  17. public static final int Y_MASK = (Integer.MAX_VALUE >> 16);
  18.  
  19. /**
  20. * PLAYER
  21. * [0] = player-x, player-y
  22. *
  23. * BOXES (for n>0)
  24. * [n] = nth-box-x (the first 16bits), nth-box-y (the second 16bits)
  25. */
  26. int player;
  27. long positions;
  28.  
  29. /**
  30. * Extract minimal state from 'board'
  31. * @param board
  32. */
  33.  
  34. /**
  35. * Extract minimal state from 'board'
  36. * @param board
  37. */
  38. public MyState(BoardCompact board) {
  39. player = getPacked(board.playerX, board.playerY);
  40. positions = 0;
  41. for (int x = 0; x < board.width(); ++x) {
  42. for (int y = 0; y < board.height(); ++y) {
  43. if (CTile.isSomeBox(board.tile(x, y))) {
  44. positions |= (1L << toBit(x, y));
  45. }
  46. }
  47. }
  48. }
  49.  
  50. public MyState(MyState state) {
  51. this.player = state.player;
  52. this.positions = state.positions;
  53. }
  54.  
  55. public boolean containsBox(long val) {
  56. return (positions & val) != 0;
  57. }
  58.  
  59. public void reverseMove(int dirVal) {
  60. EDirection dir = EDirection.arrows()[(dirVal >> 1)];
  61. int currCellX = getX(player);
  62. int currCellY = getY(player);
  63. long currBit = (1L << toBit(currCellX, currCellY));
  64. int prevPacked = getPacked(currCellX - dir.dX, currCellY - dir.dY);
  65. updatePlayer(prevPacked);
  66.  
  67. if ((dirVal & 1) == 1) {
  68. long nextBit = (1L << toBit(currCellX + dir.dX, currCellY + dir.dY));
  69. updateBit(nextBit, currBit);
  70. }
  71. }
  72.  
  73. public void updatePlayer(int newVal) {
  74. player = newVal;
  75. }
  76.  
  77. public void updateBit(long oldBit, long newBit) {
  78. positions ^= oldBit;
  79. positions |= newBit;
  80. }
  81.  
  82. /**
  83. * Packs [x;y] into single integer.
  84. * @param x
  85. * @param y
  86. * @return
  87. */
  88. public int getPacked(int x, int y) {
  89. return x << 16 | y;
  90. }
  91.  
  92. /**
  93. * Returns X coordinate from packed value.
  94. * @param packed
  95. * @return
  96. */
  97. public int getX(int packed) {
  98. return packed >> 16;
  99. }
  100.  
  101. /**
  102. * Returns Y coordinate from packed value.
  103. * @param packed
  104. * @return
  105. */
  106. public int getY(int packed) {
  107. return packed & Y_MASK;
  108. }
  109.  
  110. public int hashCode() {
  111. return (int)(positions % (1e9 + 7)) + (player << 16);
  112. }
  113.  
  114. public int toBit(int x, int y) {
  115. return bitVal[x][y];
  116. }
  117.  
  118. @Override
  119. public boolean equals(Object o) {
  120. if (this == o) return true;
  121. if (o == null || getClass() != o.getClass()) return false;
  122. MyState myState = (MyState) o;
  123. return player == myState.player && positions == myState.positions;
  124. }
  125.  
  126. @Override
  127. public String toString() {
  128. int pX = getX(player);
  129. int pY = getY(player);
  130. String s = pX + " " + pY + "\n";
  131. for (int i = 0; i < 64; ++i) {
  132. if ((positions & (1L << i)) != 0) {
  133. int x = getXbit(i);
  134. int y = getYbit(i);
  135. s += Integer.toString(x) + " " + Integer.toString(y) + "\n";
  136. }
  137. }
  138. s += "-------------\n";
  139. return s;
  140. }
  141.  
  142. int getXbit(int bit) {
  143. return xValue[bit];
  144. }
  145.  
  146. int getYbit(int bit) {
  147. return yValue[bit];
  148. }
  149. }
  150.  
  151.  
  152. static class Node implements Comparable<Node> {
  153. public Node(MyState state, int action, int g, int h) {
  154. this.state = state;
  155. this.action = action;
  156. this.g = g;
  157. this.h = h;
  158. }
  159.  
  160. MyState state;
  161. int action;
  162.  
  163. int g, h;
  164.  
  165. @Override
  166. public int compareTo(Node other) {
  167. if (g + h == other.g + other.h) {
  168. return Integer.compare(h, other.h);
  169. }
  170. return Integer.compare(g + h, other.g + other.h);
  171. }
  172. }
  173.  
  174. static protected BoardCompact board;
  175. static long endGoal;
  176. protected int searchedNodes;
  177. private static int[] boxesX;
  178. private static int[] boxesY;
  179.  
  180. static boolean[][] dead;
  181.  
  182. static int[][] bfsDist;
  183. private static int[] xValue;
  184. private static int[] yValue;
  185. private static int[][] bitVal;
  186.  
  187.  
  188. private void computeBfs() {
  189. Queue<int[]> q = new LinkedList<>();
  190. for (int x = 0; x < board.width(); ++x)
  191. for (int y = 0; y < board.height(); ++y) {
  192. if (CTile.forSomeBox(board.tile(x, y))) {
  193. bfsDist[x][y] = 0;
  194. q.offer(new int[]{x, y});
  195. } else {
  196. bfsDist[x][y] = -1;
  197. }
  198. }
  199. while (!q.isEmpty()) {
  200. int[] cell = q.poll();
  201. for (EDirection dir: EDirection.arrows()) {
  202. int neighX = cell[0] + dir.dX;
  203. int neighY = cell[1] + dir.dY;
  204. if (!CTile.isWall(board.tile(cell[0], cell[1])) && bfsDist[neighX][neighY] == -1) {
  205. bfsDist[neighX][neighY] = 1 + bfsDist[cell[0]][cell[1]];
  206. q.offer(new int[]{neighX, neighY});
  207. }
  208. }
  209. }
  210. }
  211.  
  212. private int computeBfsHeuristic() {
  213. int minCost = 0;
  214. for (int i = 0; i < boxesX.length; ++i) {
  215. if (bfsDist[boxesX[i]][boxesY[i]] == -1)
  216. return -1;
  217. minCost += bfsDist[boxesX[i]][boxesY[i]];
  218. }
  219. return minCost;
  220. }
  221.  
  222. private int computeHeuristic() {
  223. int boxes = 0;
  224. endGoal = 0;
  225. for (int i = 0; i < board.height(); ++i)
  226. for (int j = 0; j < board.width(); ++j) {
  227. if (CTile.forSomeBox(board.tiles[j][i])) {
  228. endGoal |= (1L << bitVal[j][i]);
  229. }
  230. if (CTile.isSomeBox(board.tiles[j][i])) {
  231.  
  232. if (dead[j][i]) return -1;
  233.  
  234. boxesX[boxes] = j;
  235. boxesY[boxes] = i;
  236. ++boxes;
  237. }
  238. }
  239. return computeBfsHeuristic();
  240. }
  241.  
  242. @Override
  243. protected List<EDirection> think(BoardCompact board) {
  244. MyAgent.board = board.clone();
  245. bfsDist = new int[board.width()][board.height()];
  246. bitVal = new int[board.width()][board.height()];
  247. xValue = new int[board.width() * board.height()];
  248. yValue = new int[board.width() * board.height()];
  249. for (int x = 1; x < board.width() - 1; ++x)
  250. for (int y = 1; y < board.height() - 1; ++y) {
  251. int val = (y - 1) * (board.width() - 2) + (x - 1);
  252. bitVal[x][y] = val;
  253. xValue[val] = x;
  254. yValue[val] = y;
  255. }
  256. computeBfs();
  257. boxesX = new int[board.boxCount];
  258. boxesY = new int[board.boxCount];
  259. searchedNodes = 0;
  260. long searchStartMillis = System.currentTimeMillis();
  261.  
  262. List<EDirection> result = AStar();
  263.  
  264. long searchTime = System.currentTimeMillis() - searchStartMillis;
  265.  
  266. if (verbose) {
  267. out.println("Nodes visited: " + searchedNodes);
  268. out.printf("Performance: %.1f nodes/sec\n",
  269. ((double)searchedNodes / (double)searchTime * 1000));
  270. }
  271.  
  272. return result.isEmpty() ? null : result;
  273. }
  274.  
  275. static boolean isVictory(MyState state) {
  276. return state.positions == endGoal;
  277. }
  278.  
  279. private List<EDirection> AStar() {
  280. dead = DeadSquareDetector.detect(board);
  281. PriorityQueue<Node> pq = new PriorityQueue<>();
  282. pq.add(new Node(new MyState(board), -1, 0, computeHeuristic()));
  283. HashMap<MyState, Integer> from = new HashMap<>();
  284. MyState goal = null;
  285. int k = 0;
  286. while (!pq.isEmpty()) {
  287. Node node = pq.poll();
  288. searchedNodes++;
  289. if (from.containsKey(node.state))
  290. continue;
  291.  
  292. from.put(node.state, node.action);
  293.  
  294. if (isVictory(node.state)) {
  295. goal = node.state;
  296. k = node.g;
  297. break;
  298. }
  299.  
  300. int playerX = node.state.getX(node.state.player);
  301. int playerY = node.state.getY(node.state.player);
  302.  
  303. for (EDirection dir: EDirection.arrows()) {
  304. int neighX = playerX + dir.dX;
  305. int neighY = playerY + dir.dY;
  306. if (CTile.isWall(board.tiles[neighX][neighY]))
  307. continue;
  308. int movedBox = node.state.getPacked(neighX, neighY);
  309. int oldBit = node.state.toBit(neighX, neighY);
  310. long boxBit = (1L << oldBit);
  311. if (node.state.containsBox(boxBit)) {
  312. int newBoxPosX = neighX + dir.dX;
  313. int newBoxPosY = neighY + dir.dY;
  314. int newBit = node.state.toBit(newBoxPosX, newBoxPosY);
  315. long freeSpaceBit = (1L << newBit);
  316. if (!CTile.isWall(board.tiles[newBoxPosX][newBoxPosY]) && !node.state.containsBox(freeSpaceBit)) {
  317. if (bfsDist[newBoxPosX][newBoxPosY] == -1 || dead[newBoxPosX][newBoxPosY])
  318. continue;
  319. MyState newState = new MyState(node.state);
  320. newState.updatePlayer(movedBox);
  321. newState.updateBit((1L << oldBit), (1L << newBit));
  322. if (!from.containsKey(newState)) {
  323. int heuristic = node.h - bfsDist[neighX][neighY] + bfsDist[newBoxPosX][newBoxPosY];
  324. pq.add(new Node(newState, (dir.index << 1) | 1, node.g + 1, heuristic));
  325. }
  326. }
  327. } else {
  328. MyState newState = new MyState(node.state);
  329. newState.updatePlayer(movedBox);
  330. if (!from.containsKey(newState)) {
  331. pq.add(new Node(newState, (dir.index << 1), node.g + 1, node.h));
  332. }
  333. }
  334. }
  335. }
  336.  
  337. List<EDirection> result = new ArrayList<>();
  338. while (k > 0) {
  339. int dir = from.get(goal);
  340. goal = new MyState(goal);
  341. result.add(EDirection.arrows()[dir >> 1]);
  342. goal.reverseMove(dir);
  343. k--;
  344. }
  345. Collections.reverse(result);
  346. return result;
  347. }
  348. }
  349.  
  350. class DeadSquareDetector {
  351.  
  352. static boolean[][] detect(BoardCompact board) {
  353. boolean[][] dead = new boolean[board.width()][board.height()];
  354. Queue<int[]> Q = new LinkedList<>();
  355. for (int x = 0; x < board.width(); ++x)
  356. for (int y = 0; y < board.height(); ++y)
  357. if (CTile.forSomeBox(board.tile(x, y))) {
  358. Q.offer(new int[]{x, y});
  359. dead[x][y] = false;
  360. } else {
  361. dead[x][y] = true;
  362. }
  363. while (!Q.isEmpty()) {
  364.  
  365. int[] cell = Q.poll();
  366. for (EDirection dir: EDirection.arrows()) {
  367. int neighX = cell[0]+ dir.dX;
  368. int neighY = cell[1] + dir.dY;
  369. if (!CTile.isWall(board.tile(neighX, neighY)) && dead[neighX][neighY]) {
  370. int newNeighX = neighX + dir.dX;
  371. int newNeighY = neighY + dir.dY;
  372. if (!CTile.isWall(board.tile(newNeighX, newNeighY))) {
  373. Q.offer(new int[]{neighX, neighY});
  374. dead[neighX][neighY] = false;
  375. }
  376. }
  377. }
  378.  
  379. }
  380. return dead;
  381. }
  382. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement