|
- package SnakePkg;
-
- import java.util.Random;
-
- /**
- * The game's board representation
- * @author Christos Choutouridis 8997
- */
- public class Board {
- /** @name Constructors */
- /** @{ */
- /** Default ctor */
- Board () {
- N = M =0;
- tiles = null;
- snakes = null;
- ladders = null;
- apples = null;
- }
-
- /**
- * Main constructor
- * We make some simple input checking before memory allocation.
- * @note
- * May throw BadBoardInput
- */
- Board (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples)
- throws BadBoardInput {
- // Input checking
- if (numOfApples + numOfLadders*2 + numOfSnakes*2 >= N*M/2)
- throw new BadBoardInput("Too many Apples, Snakes and ladders");
- // Init the board object
- setN (N); // Input checked version (may throw)
- setM (M); // Input checked version (may throw)
- tiles = new int[N][M];
- snakes = new Snake[numOfSnakes];
- ladders = new Ladder[numOfLadders];
- apples = new Apple[numOfApples];
- }
-
- /**
- * Copy constructor. We make a deep copy of B and we trust B's
- * data to be valid
- * @note We don't use clone as long as we don't inherit Cloneable iface
- */
- Board (Board B) {
- this.N = B.getN();
- this.M = B.getM();
- tiles = new int[N][M];
- snakes = new Snake[B.getSnakes().length];
- ladders = new Ladder[B.getLadders().length];
- apples = new Apple[B.getApples().length];
- // Copy B's guts
- for (int i =0 ; i<N ; ++i)
- for (int j =0 ; j<M ; ++j)
- tiles[i][j] = B.getTiles()[i][j];
- for (int i =0 ; i<B.getSnakes().length ; ++i)
- snakes[i] = B.getSnakes()[i];
- for (int i =0 ; i<B.getLadders().length ; ++i)
- ladders[i] = B.getLadders()[i];
- for (int i =0 ; i<B.getApples().length ; ++i)
- apples[i] = B.getApples()[i];
- }
- /** @} */
-
- /** @name Get/Set interface */
- /** @{ */
-
- /** Get value N */
- int getN () { return N; }
- /**
- * Set value N
- * @throws BadBoardInput
- */
- void setN (int N) throws BadBoardInput {
- // Input checking
- if (N<=0)
- throw new BadBoardInput("N is zero or Less");
- this.N = N;
- }
-
- /** Get value M */
- int getM () { return M; }
- /**
- * Set value M
- * @throws BadBoardInput
- */
- void setM (int M) throws BadBoardInput {
- // Input checking
- if (M<=0)
- throw new BadBoardInput("M is zero or Less");
- this.M = M;
- }
-
- /** Get reference to tiles */
- int[][] getTiles () { return tiles; }
-
- /**
- * Set tiles (deep copy)
- * @param tiles Source of tiles to use
- * @throws BadBoardInput
- */
- void setTiles (int[][] tiles) throws BadBoardInput {
- // Input checking
- if (tiles.length != N && tiles[0].length != M)
- throw new BadBoardInput("tiles size missmatch");
- // Check if we need allocation
- if (this.tiles == null)
- this.tiles = new int[N][M];
- // Assign values (deep copy)
- for (int i =0 ; i<N ; ++i)
- for (int j =0 ; j<M ; ++j)
- this.tiles[i][j] = tiles[i][j];
- }
-
- /** Get reference to snakes */
- Snake[] getSnakes() { return snakes; }
- /**
- * Set snakes (deep copy)
- * @param snakes Source of snakes to use
- * @throws BadBoardInput
- * @note Requires Snake copy contructor
- */
- void setSnakes(Snake[] snakes) throws BadBoardInput {
- // Check if we need allocation
- if (this.snakes == null)
- this.snakes = new Snake[snakes.length];
- // Input checking
- if (this.snakes.length != snakes.length)
- throw new BadBoardInput("snakes size missmatch");
- // Assign values (deep copy)
- for (int i =0 ; i<this.snakes.length ; ++i)
- this.snakes[i] = new Snake(snakes[i]);
- }
-
- /** Get reference to ladders */
- Ladder[] getLadders() { return ladders; }
- /**
- * Set ladders (deep copy)
- * @param ladders Source of snakes to use
- * @throws BadBoardInput
- * @note Requires Ladder copy contructor
- */
- void setLadders (Ladder[] ladders) throws BadBoardInput {
- // Check if we need allocation
- if (this.ladders == null)
- this.ladders = new Ladder[ladders.length];
- // Input checking
- if (this.ladders.length != ladders.length)
- throw new BadBoardInput("ladders size missmatch");
- // Assign values (deep copy)
- for (int i =0 ; i<this.ladders.length ; ++i)
- this.ladders[i] = new Ladder(ladders[i]);
- }
-
- /** Get reference to apples */
- Apple[] getApples() { return apples; }
- /**
- * Set apples (deep copy)
- * @param apples Source of snakes to use
- * @throws BadBoardInput
- * @note Requires Apple copy contructor
- */
- void setApples (Apple[] apples) throws BadBoardInput {
- // Check if we need allocation
- if (this.apples == null)
- this.apples = new Apple[apples.length];
- // Input checking
- if (this.apples.length != apples.length)
- throw new BadBoardInput("ladders size missmatch");
- // Assign values (deep copy)
- for (int i =0 ; i<this.apples.length ; ++i)
- this.apples[i] = new Apple(apples[i]);
- }
- /** @} */
-
- /** @name Exposed API members */
- /** @{ */
-
-
- /**
- * Create a playable board for the game
- */
- void createBoard () {
- _tile_numbering (); // Create tile numbering
- _place_snakes (); // Place snakes
- _place_apples (); // Place Apples
- _place_ladders (); // place ladders
- }
-
- /**
- * make and PRINT element boards
- */
- void createElementBoard () {
- String[][] elementBoardSnakes = new String[N][M];
- String[][] elementBoardLadders = new String[N][M];
- String[][] elementBoardApples = new String[N][M];
-
- _makeElementSnakes (elementBoardSnakes);
- _makeElementLadders (elementBoardLadders);
- _makeElementApples (elementBoardApples);
-
- _printElement (elementBoardSnakes, "elementBoardSnakes");
- _printElement (elementBoardLadders, "elementBoardLadders");
- _printElement (elementBoardApples, "elementBoardApples");
- }
- /** @} */
-
-
- /** @name Private api */
- /**@{ */
-
- /**
- * @brief
- * Create the tile numbering
- * We use a starting point the tile[0][0] and as finish point
- * the tile[N-1][M-1]
- */
- private void _tile_numbering () {
- for (int i=0, tile =1 ; i<N ; ++i) {
- if (i%2 == 0) {
- // Even row, go right
- for (int j=0 ; j<M ; ++j)
- tiles[i][j] = tile++;
- }
- else {
- // Odd row, go left
- for (int j=M-1 ; j>=0 ; --j)
- tiles[i][j] = tile++;
- }
- }
- }
-
- /**
- * @brief
- * Place the snakes on the board
- * The only constrain at this point is that snake tails must be
- * below heads and in different tiles
- */
- private void _place_snakes () {
- int [] head = new int [snakes.length]; // temporary place holder for heads
- int [] tail = new int [snakes.length]; // temporary place holder for tails
- for (int i =0, tile =0 ; i<snakes.length ; ++i) {
- // Keep getting heads until they are different from the previous
- do
- tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
- while (_search (head, tile) >= 0);
- head[i] = tile;
- tail[i] = (int)(Math.random() * (head[i] - head[i]%M)); // Don't use heads row and up for tail
- snakes[i] = new Snake(i, head[i], tail[i]); // Allocate snake
- }
- }
-
- /**
- * @brief
- * Place apples on the board
- * At this point we have snakes. The constrains here are
- * that apples have to lie on different tiles and not in some
- * snake's head
- */
- private void _place_apples () {
- int [] apple_tiles = new int [apples.length]; // temporary placeholder for heads
- int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
- for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
- snake_tiles[i] = snakes[i].getHeadId();
-
- for (int i =0, tile =0 ; i<apples.length ; ++i) {
- // Keep getting tiles until they are different from the previous
- // and not in some snake's head
- do
- tile = (int) (Math.random() * (N * M));
- while ((_search (apple_tiles, tile) >= 0) ||
- (_search (snake_tiles, tile) >= 0));
- apple_tiles[i] = tile;
- int points = (int)(Math.random() *10) * 5; // get points
- boolean red = (boolean)(Math.random() >=0.5); // get color
- // Allocate apple
- if (red)
- apples[i] = new Apple(i, tile, "red", points);
- else
- apples[i] = new Apple(i, tile, "black", -points);
- }
- }
-
- /**
- * @brief
- * Place ladders on board
- * At this point we have snakes and apples.
- * @note
- * We add a constrain for ladder so its up-setp has to be different from a
- * snake's head tile. This ensures the each ladder and snake are independent
- */
- private void _place_ladders () {
- int [] upstep = new int [ladders.length]; // temporary place holder for up-steps
- int [] downstep = new int [ladders.length]; // temporary place holder for down-step
- int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
- for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
- snake_tiles[i] = snakes[i].getHeadId();
-
- for (int i =0, tile =0 ; i<ladders.length ; ++i) {
- // Keep getting up-steps until they are different from the previous
- // and not in some snake's head
- do
- tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
- while ((_search (upstep, tile) >= 0) ||
- (_search (snake_tiles, tile) >= 0));
- upstep[i] = tile;
- downstep[i] = (int)(Math.random() * (upstep[i] - upstep[i]%M));
- //^ Don't use up-step row and up for down-step
- ladders[i] = new Ladder (i, upstep[i], downstep[i]); // Allocate ladder
- }
- }
-
- /**
- * Make element array of snakes
- * @param elemSnakes
- */
- private void _makeElementSnakes (String[][] elemSnakes) {
- int [] head_tiles = new int [snakes.length]; // array with snake head tiles
- int [] tail_tiles = new int [snakes.length]; // array with snake head tiles
- int sn =-1;
- // Load snake head tiles
- for (int i =0 ; i<snakes.length ; ++i) {
- head_tiles[i] = snakes[i].getHeadId();
- tail_tiles[i] = snakes[i].getTailId();
- }
-
- // Search all tiles for snake heads and tails
- for (int i =0; i<N ; ++i) {
- for (int j =0 ; j<M ; ++j) {
- if ((sn = _search (head_tiles, tiles[i][j])) >= 0)
- elemSnakes[i][j] = "SH" + sn;
- else if ((sn = _search (tail_tiles, tiles[i][j])) >= 0)
- elemSnakes[i][j] = "ST" + sn;
- else
- elemSnakes[i][j] = "___";
- }
- }
- }
-
- /**
- * Make element array of ladders
- * @param elemLadders
- */
- private void _makeElementLadders (String[][] elemLadders) {
- int [] up_tiles = new int [ladders.length]; // array with ladder up-step tiles
- int [] down_tiles = new int [ladders.length]; // array with ladder down-step tiles
- int sn =-1;
- // Load ladder tiles
- for (int i =0 ; i<ladders.length ; ++i) {
- up_tiles[i] = ladders[i].getUpStepId();
- down_tiles[i] = ladders[i].getDownStepId();
- }
-
- // Search all tiles for snake heads and tails
- for (int i =0; i<N ; ++i) {
- for (int j =0 ; j<M ; ++j) {
- if ((sn = _search (up_tiles, tiles[i][j])) >= 0)
- elemLadders[i][j] = "LU" + sn;
- else if ((sn = _search (down_tiles, tiles[i][j])) >= 0)
- elemLadders[i][j] = "LD" + sn;
- else
- elemLadders[i][j] = "___";
- }
- }
- }
-
- /**
- * Make element array of apples
- * @param elemApples
- */
- private void _makeElementApples (String[][] elemApples) {
- int [] red_tiles = new int [apples.length]; // array with red apple tiles
- int [] black_tiles = new int [apples.length]; // array with black apple tiles
- int sn =-1;
- // Load apple tiles
- for (int i =0 ; i<apples.length ; ++i) {
- if (apples[i].getColor() == "red")
- red_tiles[i] = apples[i].getAppleTileId();
- else
- black_tiles[i] = apples[i].getAppleTileId();
- }
-
- // Search all tiles for snake heads and tails
- for (int i =0; i<N ; ++i) {
- for (int j =0 ; j<M ; ++j) {
- if ((sn = _search (red_tiles, tiles[i][j])) >= 0)
- elemApples[i][j] = "AR" + sn;
- else if ((sn = _search (black_tiles, tiles[i][j])) >= 0)
- elemApples[i][j] = "AB" + sn;
- else
- elemApples[i][j] = "___";
- }
- }
- }
-
- /**
- * Print element array
- * @param elem The element array to print
- * @param caption The caption
- * @note
- * As long as we use tiles[0][0] for first tile, this method
- * has to print in reverse Y-axis order. For ex:
- * 16 15 14 13
- * 09 10 11 12
- * 08 07 06 05
- * 01 02 03 04
- */
- private void _printElement (String[][] elem, String caption) {
- System.out.print(caption);
- for (int i=N-1 ; i>=0 ; --i) {
- System.out.println("");
- System.out.print(" ");
- for (int j =0 ; j<M ; ++j)
- System.out.print(elem[i][j] + " ");
- }
- System.out.println("");
- System.out.println("");
- }
-
- /** Search algorithm
- * @param array Array to search
- * @param elem Element of type T to find inside of array
- * @return The status of the operation
- * @arg -1 Element not found
- * @arg >=0 Element found
- */
- private int _search (int[] array, int elem) {
- for (int i=0 ; i<array.length ; ++i)
- if (elem == array[i])
- return i;
- return -1;
- }
- /**@} */
-
- /** @name Data members (private) */
- /** @{ */
- private int N; //!< Board's row count
- private int M; //!< Board's Column count
- private int[][] tiles; //!< Board's tiles
- private Snake[] snakes; //!< Board's snakes
- private Ladder[] ladders; //!< Board's ladders
- private Apple[] apples; //!< Board's apples
- /** @} */
- }
-
- class BadBoardInput extends Exception {
- BadBoardInput() {}
- BadBoardInput(String str) { super(str); }
- //static final long SerialVersionUIDAdder = 0;
- }
|