A java snake game for A.U.TH. Data structures class
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

452 lignes
15 KiB

  1. package SnakePkg;
  2. import java.util.Random;
  3. /**
  4. * The game's board representation
  5. * @author Christos Choutouridis 8997
  6. */
  7. public class Board {
  8. /** @name Constructors */
  9. /** @{ */
  10. /** Default ctor */
  11. Board () {
  12. N = M =0;
  13. tiles = null;
  14. snakes = null;
  15. ladders = null;
  16. apples = null;
  17. }
  18. /**
  19. * Main constructor
  20. * We make some simple input checking before memory allocation.
  21. * @note
  22. * May throw BadBoardInput
  23. */
  24. Board (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples)
  25. throws BadBoardInput {
  26. // Input checking
  27. if (numOfApples + numOfLadders*2 + numOfSnakes*2 >= N*M/2)
  28. throw new BadBoardInput("Too many Apples, Snakes and ladders");
  29. // Init the board object
  30. setN (N); // Input checked version (may throw)
  31. setM (M); // Input checked version (may throw)
  32. tiles = new int[N][M];
  33. snakes = new Snake[numOfSnakes];
  34. ladders = new Ladder[numOfLadders];
  35. apples = new Apple[numOfApples];
  36. }
  37. /**
  38. * Copy constructor. We make a deep copy of B and we trust B's
  39. * data to be valid
  40. * @note We don't use clone as long as we don't inherit Cloneable iface
  41. */
  42. Board (Board B) {
  43. this.N = B.getN();
  44. this.M = B.getM();
  45. tiles = new int[N][M];
  46. snakes = new Snake[B.getSnakes().length];
  47. ladders = new Ladder[B.getLadders().length];
  48. apples = new Apple[B.getApples().length];
  49. // Copy B's guts
  50. for (int i =0 ; i<N ; ++i)
  51. for (int j =0 ; j<M ; ++j)
  52. tiles[i][j] = B.getTiles()[i][j];
  53. for (int i =0 ; i<B.getSnakes().length ; ++i)
  54. snakes[i] = B.getSnakes()[i];
  55. for (int i =0 ; i<B.getLadders().length ; ++i)
  56. ladders[i] = B.getLadders()[i];
  57. for (int i =0 ; i<B.getApples().length ; ++i)
  58. apples[i] = B.getApples()[i];
  59. }
  60. /** @} */
  61. /** @name Get/Set interface */
  62. /** @{ */
  63. /** Get value N */
  64. int getN () { return N; }
  65. /**
  66. * Set value N
  67. * @throws BadBoardInput
  68. */
  69. void setN (int N) throws BadBoardInput {
  70. // Input checking
  71. if (N<=0)
  72. throw new BadBoardInput("N is zero or Less");
  73. this.N = N;
  74. }
  75. /** Get value M */
  76. int getM () { return M; }
  77. /**
  78. * Set value M
  79. * @throws BadBoardInput
  80. */
  81. void setM (int M) throws BadBoardInput {
  82. // Input checking
  83. if (M<=0)
  84. throw new BadBoardInput("M is zero or Less");
  85. this.M = M;
  86. }
  87. /** Get reference to tiles */
  88. int[][] getTiles () { return tiles; }
  89. /**
  90. * Set tiles (deep copy)
  91. * @param tiles Source of tiles to use
  92. * @throws BadBoardInput
  93. */
  94. void setTiles (int[][] tiles) throws BadBoardInput {
  95. // Input checking
  96. if (tiles.length != N && tiles[0].length != M)
  97. throw new BadBoardInput("tiles size missmatch");
  98. // Check if we need allocation
  99. if (this.tiles == null)
  100. this.tiles = new int[N][M];
  101. // Assign values (deep copy)
  102. for (int i =0 ; i<N ; ++i)
  103. for (int j =0 ; j<M ; ++j)
  104. this.tiles[i][j] = tiles[i][j];
  105. }
  106. /** Get reference to snakes */
  107. Snake[] getSnakes() { return snakes; }
  108. /**
  109. * Set snakes (deep copy)
  110. * @param snakes Source of snakes to use
  111. * @throws BadBoardInput
  112. * @note Requires Snake copy contructor
  113. */
  114. void setSnakes(Snake[] snakes) throws BadBoardInput {
  115. // Check if we need allocation
  116. if (this.snakes == null)
  117. this.snakes = new Snake[snakes.length];
  118. // Input checking
  119. if (this.snakes.length != snakes.length)
  120. throw new BadBoardInput("snakes size missmatch");
  121. // Assign values (deep copy)
  122. for (int i =0 ; i<this.snakes.length ; ++i)
  123. this.snakes[i] = new Snake(snakes[i]);
  124. }
  125. /** Get reference to ladders */
  126. Ladder[] getLadders() { return ladders; }
  127. /**
  128. * Set ladders (deep copy)
  129. * @param ladders Source of snakes to use
  130. * @throws BadBoardInput
  131. * @note Requires Ladder copy contructor
  132. */
  133. void setLadders (Ladder[] ladders) throws BadBoardInput {
  134. // Check if we need allocation
  135. if (this.ladders == null)
  136. this.ladders = new Ladder[ladders.length];
  137. // Input checking
  138. if (this.ladders.length != ladders.length)
  139. throw new BadBoardInput("ladders size missmatch");
  140. // Assign values (deep copy)
  141. for (int i =0 ; i<this.ladders.length ; ++i)
  142. this.ladders[i] = new Ladder(ladders[i]);
  143. }
  144. /** Get reference to apples */
  145. Apple[] getApples() { return apples; }
  146. /**
  147. * Set apples (deep copy)
  148. * @param apples Source of snakes to use
  149. * @throws BadBoardInput
  150. * @note Requires Apple copy contructor
  151. */
  152. void setApples (Apple[] apples) throws BadBoardInput {
  153. // Check if we need allocation
  154. if (this.apples == null)
  155. this.apples = new Apple[apples.length];
  156. // Input checking
  157. if (this.apples.length != apples.length)
  158. throw new BadBoardInput("ladders size missmatch");
  159. // Assign values (deep copy)
  160. for (int i =0 ; i<this.apples.length ; ++i)
  161. this.apples[i] = new Apple(apples[i]);
  162. }
  163. /** @} */
  164. /** @name Exposed API members */
  165. /** @{ */
  166. /**
  167. * Create a playable board for the game
  168. */
  169. void createBoard () {
  170. _tile_numbering (); // Create tile numbering
  171. _place_snakes (); // Place snakes
  172. _place_apples (); // Place Apples
  173. _place_ladders (); // place ladders
  174. }
  175. /**
  176. * make and PRINT element boards
  177. */
  178. void createElementBoard () {
  179. String[][] elementBoardSnakes = new String[N][M];
  180. String[][] elementBoardLadders = new String[N][M];
  181. String[][] elementBoardApples = new String[N][M];
  182. _makeElementSnakes (elementBoardSnakes);
  183. _makeElementLadders (elementBoardLadders);
  184. _makeElementApples (elementBoardApples);
  185. _printElement (elementBoardSnakes, "elementBoardSnakes");
  186. _printElement (elementBoardLadders, "elementBoardLadders");
  187. _printElement (elementBoardApples, "elementBoardApples");
  188. }
  189. /** @} */
  190. /** @name Private api */
  191. /**@{ */
  192. /**
  193. * @brief
  194. * Create the tile numbering
  195. * We use a starting point the tile[0][0] and as finish point
  196. * the tile[N-1][M-1]
  197. */
  198. private void _tile_numbering () {
  199. for (int i=0, tile =1 ; i<N ; ++i) {
  200. if (i%2 == 0) {
  201. // Even row, go right
  202. for (int j=0 ; j<M ; ++j)
  203. tiles[i][j] = tile++;
  204. }
  205. else {
  206. // Odd row, go left
  207. for (int j=M-1 ; j>=0 ; --j)
  208. tiles[i][j] = tile++;
  209. }
  210. }
  211. }
  212. /**
  213. * @brief
  214. * Place the snakes on the board
  215. * The only constrain at this point is that snake tails must be
  216. * below heads and in different tiles
  217. */
  218. private void _place_snakes () {
  219. int [] head = new int [snakes.length]; // temporary place holder for heads
  220. int [] tail = new int [snakes.length]; // temporary place holder for tails
  221. for (int i =0, tile =0 ; i<snakes.length ; ++i) {
  222. // Keep getting heads until they are different from the previous
  223. do
  224. tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
  225. while (_search (head, tile) >= 0);
  226. head[i] = tile;
  227. tail[i] = (int)(Math.random() * (head[i] - head[i]%M)); // Don't use heads row and up for tail
  228. snakes[i] = new Snake(i, head[i], tail[i]); // Allocate snake
  229. }
  230. }
  231. /**
  232. * @brief
  233. * Place apples on the board
  234. * At this point we have snakes. The constrains here are
  235. * that apples have to lie on different tiles and not in some
  236. * snake's head
  237. */
  238. private void _place_apples () {
  239. int [] apple_tiles = new int [apples.length]; // temporary placeholder for heads
  240. int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
  241. for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
  242. snake_tiles[i] = snakes[i].getHeadId();
  243. for (int i =0, tile =0 ; i<apples.length ; ++i) {
  244. // Keep getting tiles until they are different from the previous
  245. // and not in some snake's head
  246. do
  247. tile = (int) (Math.random() * (N * M));
  248. while ((_search (apple_tiles, tile) >= 0) ||
  249. (_search (snake_tiles, tile) >= 0));
  250. apple_tiles[i] = tile;
  251. int points = (int)(Math.random() *10) * 5; // get points
  252. boolean red = (boolean)(Math.random() >=0.5); // get color
  253. // Allocate apple
  254. if (red)
  255. apples[i] = new Apple(i, tile, "red", points);
  256. else
  257. apples[i] = new Apple(i, tile, "black", -points);
  258. }
  259. }
  260. /**
  261. * @brief
  262. * Place ladders on board
  263. * At this point we have snakes and apples.
  264. * @note
  265. * We add a constrain for ladder so its up-setp has to be different from a
  266. * snake's head tile. This ensures the each ladder and snake are independent
  267. */
  268. private void _place_ladders () {
  269. int [] upstep = new int [ladders.length]; // temporary place holder for up-steps
  270. int [] downstep = new int [ladders.length]; // temporary place holder for down-step
  271. int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
  272. for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
  273. snake_tiles[i] = snakes[i].getHeadId();
  274. for (int i =0, tile =0 ; i<ladders.length ; ++i) {
  275. // Keep getting up-steps until they are different from the previous
  276. // and not in some snake's head
  277. do
  278. tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
  279. while ((_search (upstep, tile) >= 0) ||
  280. (_search (snake_tiles, tile) >= 0));
  281. upstep[i] = tile;
  282. downstep[i] = (int)(Math.random() * (upstep[i] - upstep[i]%M));
  283. //^ Don't use up-step row and up for down-step
  284. ladders[i] = new Ladder (i, upstep[i], downstep[i]); // Allocate ladder
  285. }
  286. }
  287. /**
  288. * Make element array of snakes
  289. * @param elemSnakes
  290. */
  291. private void _makeElementSnakes (String[][] elemSnakes) {
  292. int [] head_tiles = new int [snakes.length]; // array with snake head tiles
  293. int [] tail_tiles = new int [snakes.length]; // array with snake head tiles
  294. int sn =-1;
  295. // Load snake head tiles
  296. for (int i =0 ; i<snakes.length ; ++i) {
  297. head_tiles[i] = snakes[i].getHeadId();
  298. tail_tiles[i] = snakes[i].getTailId();
  299. }
  300. // Search all tiles for snake heads and tails
  301. for (int i =0; i<N ; ++i) {
  302. for (int j =0 ; j<M ; ++j) {
  303. if ((sn = _search (head_tiles, tiles[i][j])) >= 0)
  304. elemSnakes[i][j] = "SH" + sn;
  305. else if ((sn = _search (tail_tiles, tiles[i][j])) >= 0)
  306. elemSnakes[i][j] = "ST" + sn;
  307. else
  308. elemSnakes[i][j] = "___";
  309. }
  310. }
  311. }
  312. /**
  313. * Make element array of ladders
  314. * @param elemLadders
  315. */
  316. private void _makeElementLadders (String[][] elemLadders) {
  317. int [] up_tiles = new int [ladders.length]; // array with ladder up-step tiles
  318. int [] down_tiles = new int [ladders.length]; // array with ladder down-step tiles
  319. int sn =-1;
  320. // Load ladder tiles
  321. for (int i =0 ; i<ladders.length ; ++i) {
  322. up_tiles[i] = ladders[i].getUpStepId();
  323. down_tiles[i] = ladders[i].getDownStepId();
  324. }
  325. // Search all tiles for snake heads and tails
  326. for (int i =0; i<N ; ++i) {
  327. for (int j =0 ; j<M ; ++j) {
  328. if ((sn = _search (up_tiles, tiles[i][j])) >= 0)
  329. elemLadders[i][j] = "LU" + sn;
  330. else if ((sn = _search (down_tiles, tiles[i][j])) >= 0)
  331. elemLadders[i][j] = "LD" + sn;
  332. else
  333. elemLadders[i][j] = "___";
  334. }
  335. }
  336. }
  337. /**
  338. * Make element array of apples
  339. * @param elemApples
  340. */
  341. private void _makeElementApples (String[][] elemApples) {
  342. int [] red_tiles = new int [apples.length]; // array with red apple tiles
  343. int [] black_tiles = new int [apples.length]; // array with black apple tiles
  344. int sn =-1;
  345. // Load apple tiles
  346. for (int i =0 ; i<apples.length ; ++i) {
  347. if (apples[i].getColor() == "red")
  348. red_tiles[i] = apples[i].getAppleTileId();
  349. else
  350. black_tiles[i] = apples[i].getAppleTileId();
  351. }
  352. // Search all tiles for snake heads and tails
  353. for (int i =0; i<N ; ++i) {
  354. for (int j =0 ; j<M ; ++j) {
  355. if ((sn = _search (red_tiles, tiles[i][j])) >= 0)
  356. elemApples[i][j] = "AR" + sn;
  357. else if ((sn = _search (black_tiles, tiles[i][j])) >= 0)
  358. elemApples[i][j] = "AB" + sn;
  359. else
  360. elemApples[i][j] = "___";
  361. }
  362. }
  363. }
  364. /**
  365. * Print element array
  366. * @param elem The element array to print
  367. * @param caption The caption
  368. * @note
  369. * As long as we use tiles[0][0] for first tile, this method
  370. * has to print in reverse Y-axis order. For ex:
  371. * 16 15 14 13
  372. * 09 10 11 12
  373. * 08 07 06 05
  374. * 01 02 03 04
  375. */
  376. private void _printElement (String[][] elem, String caption) {
  377. System.out.print(caption);
  378. for (int i=N-1 ; i>=0 ; --i) {
  379. System.out.println("");
  380. System.out.print(" ");
  381. for (int j =0 ; j<M ; ++j)
  382. System.out.print(elem[i][j] + " ");
  383. }
  384. System.out.println("");
  385. System.out.println("");
  386. }
  387. /** Search algorithm
  388. * @param array Array to search
  389. * @param elem Element of type T to find inside of array
  390. * @return The status of the operation
  391. * @arg -1 Element not found
  392. * @arg >=0 Element found
  393. */
  394. private int _search (int[] array, int elem) {
  395. for (int i=0 ; i<array.length ; ++i)
  396. if (elem == array[i])
  397. return i;
  398. return -1;
  399. }
  400. /**@} */
  401. /** @name Data members (private) */
  402. /** @{ */
  403. private int N; //!< Board's row count
  404. private int M; //!< Board's Column count
  405. private int[][] tiles; //!< Board's tiles
  406. private Snake[] snakes; //!< Board's snakes
  407. private Ladder[] ladders; //!< Board's ladders
  408. private Apple[] apples; //!< Board's apples
  409. /** @} */
  410. }
  411. class BadBoardInput extends Exception {
  412. BadBoardInput() {}
  413. BadBoardInput(String str) { super(str); }
  414. //static final long SerialVersionUIDAdder = 0;
  415. }