A java snake game 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.

352 lines
12 KiB

  1. package net.hoo2.auth.dsproject.snake;
  2. /**
  3. * @mainpage
  4. * @title Snake game project. -- Part 3 --
  5. *
  6. * This is the code documentation page of the Snake game project.
  7. * Listed are:
  8. * * All used classes
  9. * * All member functions
  10. * * All data members
  11. *
  12. * @author Christos Choutouridis AEM:8997
  13. * @email cchoutou@ece.auth.gr
  14. */
  15. import java.util.*;
  16. /**
  17. * @class Game
  18. *
  19. * @brief This is the main control class of the game.
  20. *
  21. * This class includes the main function.Using this class's api
  22. * the user can create a board, register players and roll the game.
  23. *
  24. * @author Christos Choutouridis AEM:8997
  25. * @email cchoutou@ece.auth.gr
  26. */
  27. public class Game {
  28. /** @name Constants */
  29. /**@{ */
  30. static final int MAX_PLAYERS = 6; /**< The maximum number of allowed players in the game */
  31. static final int MAX_GAME_ROUNDS = 1000; /**< the maximum allowed round of the game */
  32. /**@} */
  33. /** @name Private data members */
  34. /** @{ */
  35. private int round; /**< The current round of the game */
  36. private Board board; /**< A reference to board */
  37. private ArrayList<Player> players; /**< A reference to players */
  38. private Map<Integer, Integer> playingOrder; /**< A Map with {PlayerID, Dice-roll} pairs
  39. @note
  40. This way of storing the playing order is unnecessary.
  41. The old style was far more better. We had a turn variable
  42. in each Player and we used to sort the players vector based on
  43. that value. This made the rest of the program simpler, faster, easer.
  44. We have adopt the above approach just because it is one of the
  45. homework requirements.
  46. */
  47. /** @} */
  48. /** @name private api */
  49. /** @{ */
  50. /**
  51. * Search the players already in the pairs vector and compare their turn to play
  52. * with the result of a dice. If there is another one with the same dice result return true.
  53. *
  54. * @param roll The dice result to check in order to find player's turn to play
  55. * @param pairs Reference to already register players and their dice result
  56. * @return True if there is another player with the same dice result
  57. */
  58. private boolean _search (int roll, ArrayList<Integer[]> pairs) {
  59. for (int i =0; i<pairs.size() ; ++i)
  60. if (pairs.get(i)[1] == roll)
  61. return true;
  62. return false;
  63. }
  64. /**
  65. * Sort the pairs vector using second parameter witch represent the
  66. * dice roll. We use bubblesort for the implementation.
  67. * @param pairs A vector with {PlayerId, dice-roll} pairs to sort
  68. */
  69. private void _sort (ArrayList<Integer[]> pairs) {
  70. Integer[] temp;
  71. for (int i=pairs.size()-1 ; i>0 ; --i) {
  72. for (int j =0 ; j<i ; ++j) {
  73. if (pairs.get(j)[1] > pairs.get(i)[1]) {
  74. temp = pairs.get(i);
  75. pairs.set(i, pairs.get(j));
  76. pairs.set(j, temp);
  77. }
  78. }
  79. }
  80. }
  81. /**
  82. * Helper function to get a player from players vector using it's ID
  83. * @param playerId The player's ID to seek
  84. * @return Reference to Player or null
  85. */
  86. private Player _getPlayer(int playerId) {
  87. for (Player p : players) {
  88. if (p.getPlayerId() == playerId)
  89. return p;
  90. }
  91. return null;
  92. }
  93. /** @} */
  94. /** @name Constructors */
  95. /** @{ */
  96. /** Default doing nothing constructor */
  97. Game () {
  98. round = 0;
  99. board = new Board();
  100. players = new ArrayList<>();
  101. playingOrder
  102. = new HashMap<Integer, Integer>();
  103. }
  104. /**
  105. * @brief The main constructor
  106. * This constructor create a board and prepares the board for the game.
  107. * After this call the user can call @ref registerPlayer()
  108. * @param N The row for the board
  109. * @param M The columns of the board
  110. * @param numOfSnakes Number of snakes to place
  111. * @param numOfLadders Number of ladders to place
  112. * @param numOfApples Number of Apples to place
  113. */
  114. Game (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples) {
  115. round = 0;
  116. // delegate constructors
  117. board = new Board (N, M, numOfSnakes, numOfLadders, numOfApples);
  118. players = new ArrayList<>();
  119. playingOrder
  120. = new HashMap<Integer, Integer>();
  121. }
  122. /** @} */
  123. /** @name Get/Set interface */
  124. /** @{ */
  125. int getRound () { return round; }
  126. void setRound (int round) { this.round = round; }
  127. /** Get reference to board */
  128. Board getBoard () { return board; }
  129. /** Set board
  130. * @param board Reference to board to use
  131. * @note This requires board must be allocated elsewhere.
  132. */
  133. void setBoard (Board board) {
  134. this.board = board;
  135. }
  136. /** Get reference to players */
  137. ArrayList<Player> getPlayers() { return players; }
  138. /**
  139. * Set players
  140. * @param players Reference to players to use
  141. * @note This requires players must be allocated elsewhere.
  142. */
  143. void setPlayers(ArrayList<Player> players) {
  144. this.players = players;
  145. }
  146. /** Get reference to playingOrder Map */
  147. Map<Integer, Integer> getPlayingOrder () { return playingOrder; }
  148. /** Set the playingOrder Map */
  149. void setPlayingOrder (Map<Integer, Integer> playingOrder) {
  150. this.playingOrder = playingOrder;
  151. }
  152. /** @} */
  153. /** @name Public functionality */
  154. /** @{ */
  155. /**
  156. * Register a player to the game
  157. * @param playerId The player ID to use
  158. * @param name The player name to use
  159. * @return The status of the operation
  160. */
  161. boolean registerPlayer (int playerId, String name) {
  162. if (players.size() >= MAX_PLAYERS)
  163. return false;
  164. players.add(new Player(playerId, name));
  165. return true;
  166. }
  167. // /**
  168. // * Register a heuristic player to the game
  169. // * @param playerId The player ID to use
  170. // * @param name The player name to use
  171. // * @return The status of the operation
  172. // */
  173. // boolean registerHeuristicPlayer (int playerId, String name) {
  174. // if (players.size() >= MAX_PLAYERS)
  175. // return false;
  176. // //players.add(new HeuristicPlayer(playerId, name, board));
  177. // players.add(new HeuristicPlayer(playerId, name));
  178. // return true;
  179. // }
  180. /**
  181. * Register a heuristic player to the game
  182. * @param playerId The player ID to use
  183. * @param name The player name to use
  184. * @return The status of the operation
  185. */
  186. boolean registerMinMaxPlayer (int playerId, String name) {
  187. if (players.size() >= MAX_PLAYERS)
  188. return false;
  189. //players.add(new HeuristicPlayer(playerId, name, board));
  190. players.add(new MinMaxPlayer(playerId, name));
  191. return true;
  192. }
  193. /**
  194. * @brief Set the playing order of players
  195. * This function emulates the classic roll of dice to decide which player
  196. * plays first which second and so on.
  197. */
  198. Map<Integer, Integer> setTurns (ArrayList<Player> players) {
  199. int[] pairData = new int[2]; // We use plain int[] to create an Integer[]
  200. Integer[] PairData; // The Integer[] to push to ArrayList<>
  201. ArrayList<Integer[]>
  202. pairList = new ArrayList<>(); // Use use ArrayList before Map in order to sort
  203. for (int d, i =0 ; i<players.size() ; ++i) {
  204. do
  205. // Keep rolling the dice until we get a unique value
  206. d = players.get(i).dice ();
  207. while (_search (d, pairList));
  208. // Make Integer[] pair
  209. pairData[0] = players.get(i).getPlayerId();
  210. pairData[1] = d;
  211. PairData = Arrays.stream(pairData)
  212. .boxed()
  213. .toArray(Integer[]::new);
  214. pairList.add(PairData); // Add to vector
  215. }
  216. // Sort playeingOrger
  217. _sort (pairList);
  218. // Make and return the Map
  219. for (int i =0 ; i<pairList.size() ; ++i) {
  220. playingOrder.put(pairList.get(i)[0], pairList.get(i)[1]);
  221. }
  222. return playingOrder;
  223. }
  224. /**
  225. * Sort the players according to their score
  226. */
  227. void scoreSort () {
  228. players.sort((p1, p2) ->
  229. Integer.compare (p1.getScore(), p2.getScore())
  230. );
  231. }
  232. /**
  233. * A game round. In each round every player plays when is his turn
  234. *
  235. * @param verbose Flag to indicate how much we print to console
  236. * @return The winner if we have one, or null
  237. */
  238. Player round (boolean verbose) {
  239. int tile;
  240. ++round; // keep track of round
  241. // traverse the players vector and move each player on the board
  242. // using a dice throw
  243. for (Integer pid : playingOrder.keySet()) {
  244. Player p = _getPlayer(pid);
  245. tile = p.getNextMove (board, p.getTile())[0];
  246. p.statistics(verbose, false);
  247. if (tile>= board.getN()*board.getM())
  248. // The first one here is the winner
  249. return p;
  250. }
  251. return null; // No one finished yet
  252. }
  253. /** @} */
  254. /**
  255. * @brief Main
  256. * As the requirements of the project suggested.
  257. * We:
  258. * * Create a game
  259. * * Manually create a board
  260. * * Register 2 players (John Doe for now)
  261. * * Place a predefined number of snakes, ladders and apples
  262. * * Deploy the game by calling @ref playOrder() and @ref round()
  263. * At the end we print the results and exit
  264. */
  265. public static void main(String[] args) {
  266. // Current project requirements
  267. int lines = 20;
  268. int columns = 10;
  269. int numOfSnakes = 3;
  270. int numOfLadders = 3;
  271. int numOfApples = 6;
  272. int numOfPlayers = 2;
  273. boolean verbose = true;
  274. // Print caption
  275. System.out.println("================== Snake Game ==================");
  276. System.out.println("Board: " +lines +"x" +columns +" with " +numOfSnakes +" snakes, "
  277. +numOfLadders +" ladders and " +numOfApples +" apples.");
  278. System.out.println("Players: " + numOfPlayers);
  279. System.out.println("");
  280. // Board creation
  281. Game game = new Game (lines, columns, numOfSnakes, numOfLadders, numOfApples);
  282. // game.getBoard().createElementBoard(); // Not explicitly required
  283. // Player registration, the one is cheater
  284. for (int i=0 ; i<numOfPlayers && i<MAX_PLAYERS; ++i) {
  285. if (i == 0)
  286. game.registerMinMaxPlayer(i+1, String.format("Player %d", i+1));
  287. else
  288. game.registerPlayer(i+1, String.format("Player %d", i+1));
  289. }
  290. game.setTurns(game.getPlayers()); // Choose play order
  291. game.board.setPlayers(game.getPlayers()); // inform the board with the players
  292. Player winner;
  293. do // Keep going until someone finishes
  294. winner = game.round (verbose);
  295. while (winner == null
  296. && game.getRound() < MAX_GAME_ROUNDS);
  297. if (game.getRound() == MAX_GAME_ROUNDS) {
  298. // Check if we finished
  299. System.out.println("Game did not finished in " + MAX_GAME_ROUNDS + " rounds. Abort.");
  300. return;
  301. }
  302. // Print the results
  303. System.out.println("*** Game finished ***");
  304. System.out.println("");
  305. System.out.println("");
  306. System.out.println("*** Game Results ***");
  307. System.out.println("Rounds: " + game.getRound());
  308. System.out.println("Winner: " + winner.getName() + " [" + winner.getScore() +" points]");
  309. System.out.println("Score: ");
  310. game.scoreSort (); // sort players based on their score
  311. for (int i=game.getPlayers().size()-1 ; i>=0 ; --i) {
  312. // Loop all players
  313. Player p = game.getPlayers().get(i);
  314. if (p == winner)
  315. System.out.println(" * " +p.getName() + ": " + p.getScore() +" points");
  316. else
  317. System.out.println(" " +p.getName() + ": " + p.getScore() +" points");
  318. }
  319. // Print the extra statistics for the heuristic player only
  320. // We use a little reflection for that
  321. for (Player p : game.getPlayers()) {
  322. if (p.getClass().getSimpleName().equals("HeuristicPlayer"))
  323. p.statistics(verbose, true);
  324. }
  325. }
  326. }