A java PacMan game application for A.U.TH (data structures class)
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.

382 lines
12 KiB

  1. package gr.auth.ee.dsproject.pacman;
  2. import java.util.ArrayList;
  3. import gr.auth.ee.dsproject.node.Globals;
  4. import gr.auth.ee.dsproject.node.Tree;
  5. import gr.auth.ee.dsproject.node.Node89978445;
  6. /**
  7. * <p>
  8. * Title: DataStructures2011
  9. * </p>
  10. *
  11. * <p>
  12. * Description: Data Structures project: year 2011-2012
  13. * </p>
  14. *
  15. * <p>
  16. * Copyright: Copyright (c) 2011
  17. * </p>
  18. *
  19. * <p>
  20. * Company: A.U.Th.
  21. * </p>
  22. *
  23. * @author Michael T. Tsapanos
  24. * @version 1.0
  25. */
  26. public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
  27. {
  28. public String getName () {
  29. return "Mine";
  30. }
  31. private int step = 1;
  32. private boolean amPrey;
  33. public Creature (boolean isPrey) {
  34. amPrey = isPrey;
  35. }
  36. /**
  37. * @brief
  38. * For any current position creates a tree for minmax alpha-beta pruning algorithm
  39. * apply the min-max algo and return the move representing by resulting node
  40. * @return
  41. * the move of pacman to play
  42. */
  43. public int calculateNextPacmanPosition (Room[][] Maze, int[] currPosition)
  44. {
  45. int [] bestPos = {-1, -1}; // Best position in maze to play
  46. int bestMove = 0;
  47. Node89978445 bestNode; // The node with the best evaluation
  48. Node89978445 cur = new Node89978445 (Maze, currPosition); // The node with the current position
  49. //make the tree
  50. createSubTreePacman (cur.getDepth (), cur, Maze, currPosition);
  51. // min-max to find best node and consequently the best position
  52. bestNode = Tree.minmaxAB (cur, Globals.MINMAXTREE_MAX_DEPTH-1, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
  53. bestPos = bestNode.getCurrentPacmanPos();
  54. // convert back to move encoding
  55. if ((bestMove = Node89978445.moveConv (bestPos, currPosition)) != Globals.INVALID_MOVE)
  56. return bestMove;
  57. else
  58. return 0;
  59. }
  60. /**
  61. * @brief
  62. * For any ghost (or root) parent node, create all child nodes representing
  63. * pacman's valid moves.
  64. * @note
  65. * This routine calls createSubTreeGhosts() called back from it recursively.
  66. * The recursion ends when the right depth is reached.
  67. */
  68. void createSubTreePacman (int depth, Node89978445 parent, Room[][] Maze, int[] curPacmanPosition)
  69. {
  70. if (depth >= Globals.MINMAXTREE_MAX_DEPTH-1)
  71. /*<
  72. * As the depth starts from 0 and MINMAXTREE_MAX_DEPTH
  73. * is strictly even, with this comparison we accept that there
  74. * is no need for a max-depth layer of ghosts-evaluation based nodes.
  75. * As soon as we accept the depth-1 layers max evaluated node.
  76. */
  77. return;
  78. else {
  79. Node89978445 newNode;
  80. Room[][] newMaze;
  81. int[] nextPosition = {-1, -1};
  82. // scan possible valid moves
  83. for (int move=0 ; move<4 ; ++move) {
  84. if ((nextPosition = Node89978445.pacmanValidMove (parent, move)) != Globals.POSITION_FALSE) {
  85. // Make a copy of the maze in order to simulate next move and move Pacman
  86. newMaze = PacmanUtilities.copy (Maze);
  87. PacmanUtilities.movePacman (newMaze, parent.getCurrentPacmanPos(), nextPosition);
  88. // Create a node for the move in the new stated game maze
  89. newNode = new Node89978445 (newMaze, nextPosition);
  90. Tree.grow (newNode, parent); // add node to the min-max search tree
  91. // call the recursive branch creator
  92. createSubTreeGhosts (newNode.getDepth (), newNode, newMaze, newNode.getCurrentGhostPos());
  93. }
  94. }
  95. }
  96. }
  97. /**
  98. * @brief
  99. * For any parent node, create all child node representing ghosts valid moves.
  100. * @note
  101. * This routine recursively call createSubTreePacman().
  102. * The recursion ends when the right depth is reached.
  103. */
  104. void createSubTreeGhosts (int depth, Node89978445 parent, Room[][] Maze, int[][] currGhostsPosition)
  105. {
  106. if (depth >= Globals.MINMAXTREE_MAX_DEPTH-1)
  107. /*<
  108. * As the depth starts from 0 and MINMAXTREE_MAX_DEPTH
  109. * is strictly even, with this comparison we accept that there
  110. * is no need for a max-depth layer of ghosts-evaluation based nodes.
  111. * As soon as we accept the depth-1 layers max evaluated node.
  112. */
  113. return;
  114. else {
  115. Node89978445 newNode;
  116. Room[][] newMaze;
  117. ArrayList<int[][]> ghostMoves;
  118. // Get all possible ghost moves
  119. ghostMoves = PacmanUtilities.allGhostMoves(Maze, currGhostsPosition);
  120. // loop all ghost moves
  121. for (int i=0 ; i<ghostMoves.size() ; ++i) {
  122. // Make a copy of the maze in order to simulate next move and move ghosts
  123. newMaze = PacmanUtilities.copy (Maze);
  124. PacmanUtilities.moveGhosts(newMaze, currGhostsPosition, ghostMoves.get(i));
  125. // Create a node for the move in the new stated game maze
  126. newNode = new Node89978445 (newMaze, parent.getCurrentPacmanPos());
  127. Tree.grow (newNode, parent); // add node to the min-max search tree
  128. //recursive call for the rest of the tree
  129. createSubTreePacman (newNode.getDepth (), newNode, newMaze, parent.getCurrentPacmanPos());
  130. }
  131. }
  132. }
  133. public int[] getPacPos (Room[][] Maze)
  134. {
  135. int[] pacmanPos = new int[2];
  136. for (int i = 0; i < PacmanUtilities.numberOfRows; i++) {
  137. for (int j = 0; j < PacmanUtilities.numberOfColumns; j++) {
  138. if (Maze[i][j].isPacman()) {
  139. pacmanPos[0] = i;
  140. pacmanPos[1] = j;
  141. return pacmanPos;
  142. }
  143. }
  144. }
  145. return pacmanPos;
  146. }
  147. public boolean[] comAvPos (Room[][] Maze, int[][] currentPos, int[] moves, int currentGhost)
  148. {
  149. boolean[] availablePositions = { true, true, true, true };
  150. int[][] newPos = new int[4][2];
  151. for (int i = 0; i < 4; i++) {
  152. if (Maze[currentPos[currentGhost][0]][currentPos[currentGhost][1]].walls[i] == 0) {
  153. availablePositions[i] = false;
  154. continue;
  155. }
  156. if (PacmanUtilities.flagColision(Maze, currentPos[currentGhost], i)) {
  157. availablePositions[i] = false;
  158. }
  159. else if (currentGhost == 0)
  160. continue;
  161. else {
  162. switch (i) {
  163. case Room.WEST:
  164. newPos[currentGhost][0] = currentPos[currentGhost][0];
  165. newPos[currentGhost][1] = currentPos[currentGhost][1] - 1;
  166. break;
  167. case Room.SOUTH:
  168. newPos[currentGhost][0] = currentPos[currentGhost][0] + 1;
  169. newPos[currentGhost][1] = currentPos[currentGhost][1];
  170. break;
  171. case Room.EAST:
  172. newPos[currentGhost][0] = currentPos[currentGhost][0];
  173. newPos[currentGhost][1] = currentPos[currentGhost][1] + 1;
  174. break;
  175. case Room.NORTH:
  176. newPos[currentGhost][0] = currentPos[currentGhost][0] - 1;
  177. newPos[currentGhost][1] = currentPos[currentGhost][1];
  178. }
  179. for (int j = (currentGhost - 1); j > -1; j--) {
  180. switch (moves[j]) {
  181. case Room.WEST:
  182. newPos[j][0] = currentPos[j][0];
  183. newPos[j][1] = currentPos[j][1] - 1;
  184. break;
  185. case Room.SOUTH:
  186. newPos[j][0] = currentPos[j][0] + 1;
  187. newPos[j][1] = currentPos[j][1];
  188. break;
  189. case Room.EAST:
  190. newPos[j][0] = currentPos[j][0];
  191. newPos[j][1] = currentPos[j][1] + 1;
  192. break;
  193. case Room.NORTH:
  194. newPos[j][0] = currentPos[j][0] - 1;
  195. newPos[j][1] = currentPos[j][1];
  196. // break;
  197. }
  198. if ((newPos[currentGhost][0] == newPos[j][0]) && (newPos[currentGhost][1] == newPos[j][1])) {
  199. availablePositions[i] = false;
  200. continue;
  201. }
  202. if ((newPos[currentGhost][0] == currentPos[j][0]) && (newPos[currentGhost][1] == currentPos[j][1]) && (newPos[j][0] == currentPos[currentGhost][0])
  203. && (newPos[j][1] == currentPos[currentGhost][1])) {
  204. availablePositions[i] = false;
  205. }
  206. }
  207. }
  208. }
  209. return availablePositions;
  210. }
  211. public int comBestPos (boolean[] availablePositions, int[] pacmanPosition, int[] currentPos)
  212. {
  213. int[] newVerticalDifference = new int[2];
  214. for (int i = 0; i < 2; i++)
  215. newVerticalDifference[i] = currentPos[i] - pacmanPosition[i];
  216. int[] distanceSquared = new int[4];
  217. for (int i = 0; i < 4; i++) {
  218. if (availablePositions[i] == true) {
  219. switch (i) {
  220. case Room.WEST:
  221. newVerticalDifference[1]--;
  222. break;
  223. case Room.SOUTH:
  224. newVerticalDifference[0]++;
  225. break;
  226. case Room.EAST:
  227. newVerticalDifference[1]++;
  228. break;
  229. case Room.NORTH:
  230. newVerticalDifference[0]--;
  231. break;
  232. }
  233. distanceSquared[i] = newVerticalDifference[0] * newVerticalDifference[0] + newVerticalDifference[1] * newVerticalDifference[1];
  234. } else
  235. distanceSquared[i] = PacmanUtilities.numberOfRows * PacmanUtilities.numberOfRows + PacmanUtilities.numberOfColumns * PacmanUtilities.numberOfColumns + 1;
  236. }
  237. int minDistance = distanceSquared[0];
  238. int minPosition = 0;
  239. for (int i = 1; i < 4; i++) {
  240. if (minDistance > distanceSquared[i]) {
  241. minDistance = distanceSquared[i];
  242. minPosition = i;
  243. }
  244. }
  245. return minPosition;
  246. }
  247. public int[] calculateNextGhostPosition (Room[][] Maze, int[][] currentPos)
  248. {
  249. int[] moves = new int[PacmanUtilities.numberOfGhosts];
  250. int[] pacmanPosition = new int[2];
  251. pacmanPosition = getPacPos(Maze);
  252. for (int i = 0; i < PacmanUtilities.numberOfGhosts; i++) {
  253. moves[i] = comBestPos(comAvPos(Maze, currentPos, moves, i), pacmanPosition, currentPos[i]);
  254. }
  255. return moves;
  256. }
  257. public boolean[] checkCollision (int[] moves, int[][] currentPos)
  258. {
  259. boolean[] collision = new boolean[PacmanUtilities.numberOfGhosts];
  260. int[][] newPos = new int[4][2];
  261. for (int i = 0; i < moves.length; i++) {
  262. if (moves[i] == 0) {
  263. if (currentPos[i][1] > 0) {
  264. newPos[i][0] = currentPos[i][0];
  265. newPos[i][1] = currentPos[i][1] - 1;
  266. } else {
  267. newPos[i][0] = currentPos[i][0];
  268. newPos[i][1] = PacmanUtilities.numberOfColumns - 1;
  269. }
  270. } else if (moves[i] == 1) {
  271. if (currentPos[i][0] < PacmanUtilities.numberOfRows - 1) {
  272. newPos[i][0] = currentPos[i][0] + 1;
  273. newPos[i][1] = currentPos[i][1];
  274. } else {
  275. newPos[i][0] = 0;
  276. newPos[i][1] = currentPos[i][1];
  277. }
  278. } else if (moves[i] == 2) {
  279. if (currentPos[i][1] < PacmanUtilities.numberOfColumns - 1) {
  280. newPos[i][0] = currentPos[i][0];
  281. newPos[i][1] = currentPos[i][1] + 1;
  282. } else {
  283. newPos[i][0] = currentPos[i][0];
  284. newPos[i][1] = 0;
  285. }
  286. } else {
  287. if (currentPos[i][0] > 0) {
  288. newPos[i][0] = currentPos[i][0] - 1;
  289. newPos[i][1] = currentPos[i][1];
  290. } else {
  291. newPos[i][0] = PacmanUtilities.numberOfRows - 1;
  292. newPos[i][1] = currentPos[i][1];
  293. }
  294. }
  295. collision[i] = false;
  296. }
  297. for (int k = 0; k < moves.length; k++) {
  298. }
  299. for (int i = 0; i < moves.length; i++) {
  300. for (int j = i + 1; j < moves.length; j++) {
  301. if (newPos[i][0] == newPos[j][0] && newPos[i][1] == newPos[j][1]) {
  302. collision[j] = true;
  303. }
  304. if (newPos[i][0] == currentPos[j][0] && newPos[i][1] == currentPos[j][1] && newPos[j][0] == currentPos[i][0] && newPos[j][1] == currentPos[i][1]) {
  305. collision[j] = true;
  306. }
  307. }
  308. }
  309. return collision;
  310. }
  311. }