Board and game are now in a playable condition
This commit is contained in:
parent
10c6792dfb
commit
1b45948ea4
@ -1,15 +1,32 @@
|
|||||||
package SnakePkg;
|
package SnakePkg;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.lang.Math;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The game's board representation
|
* @class Board
|
||||||
|
* @brief The game's board representation.
|
||||||
|
*
|
||||||
|
* The board in a square collection of tiles numbered in a
|
||||||
|
* boustrophedon (zig-zag) way. A number of snakes, ladders
|
||||||
|
* and apples which called elements are placed on the board
|
||||||
|
* for each game.
|
||||||
|
*
|
||||||
* @author Christos Choutouridis 8997
|
* @author Christos Choutouridis 8997
|
||||||
|
* @email cchoutou@ece.auth.gr
|
||||||
*/
|
*/
|
||||||
public class Board {
|
public class Board {
|
||||||
|
/** Constants */
|
||||||
|
/**@{ */
|
||||||
|
static final int POINTS_MAX = 20; /**< The maximum absolute number of points for each apple */
|
||||||
|
static final int POINTS_STEP = 5; /**< The difference between different apple points */
|
||||||
|
/**@} */
|
||||||
|
|
||||||
/** @name Constructors */
|
/** @name Constructors */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
/** Default ctor */
|
/** A doing nothing default constructor
|
||||||
|
* @warining Avoid using this constructor as it requires all setters(or copy)
|
||||||
|
* and @ref createBoard() to be called after.
|
||||||
|
*/
|
||||||
Board () {
|
Board () {
|
||||||
N = M =0;
|
N = M =0;
|
||||||
tiles = null;
|
tiles = null;
|
||||||
@ -19,47 +36,56 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main constructor
|
* @brief Creates a board for game
|
||||||
* We make some simple input checking before memory allocation.
|
*
|
||||||
* @note
|
* This constructor allocates the memory for the board and elements and
|
||||||
* May throw BadBoardInput
|
* creates a board by placing all required elements on the board.
|
||||||
|
*
|
||||||
|
* @param N The row for the board
|
||||||
|
* @param M The columns of the board
|
||||||
|
* @param numOfSnakes Number of snakes to place
|
||||||
|
* @param numOfLadders Number of ladders to place
|
||||||
|
* @param numOfApples Number of Apples to place
|
||||||
|
*
|
||||||
|
* @warning
|
||||||
|
* We call @ref createBoard() inside this constructor in order for
|
||||||
|
* the board to be in "playable condition". This is preferable by the author.
|
||||||
|
* A constructor should(if possible) to leave the object in a usable condition.
|
||||||
|
* In order to follow the project requirements we create this functionality in a
|
||||||
|
* separate function @ref createBoard(). We believe that if a user can make a
|
||||||
|
* mistake he eventually will do it sometime. Here, if we leave the createBoard()
|
||||||
|
* call to user we are enabling him to make it.
|
||||||
*/
|
*/
|
||||||
Board (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples)
|
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
|
// Init the board object
|
||||||
setN (N); // Input checked version (may throw)
|
setN (N); // Input checked version (may throw)
|
||||||
setM (M); // Input checked version (may throw)
|
setM (M); // Input checked version (may throw)
|
||||||
tiles = new int[N][M];
|
tiles = new int[N][M];
|
||||||
snakes = new Snake[numOfSnakes];
|
snakes = new Snake[numOfSnakes];
|
||||||
ladders = new Ladder[numOfLadders];
|
ladders = new Ladder[numOfLadders];
|
||||||
apples = new Apple[numOfApples];
|
apples = new Apple[numOfApples];
|
||||||
|
createBoard (); // Complete board preparation and make all the element memory allocations
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor. We make a deep copy of B and we trust B's
|
* @brief Copy constructor.
|
||||||
* data to be valid
|
* We make a deep copy of B and we trust B's data to be valid.
|
||||||
|
* @param B The board we want to copy
|
||||||
* @note We don't use clone as long as we don't inherit Cloneable iface
|
* @note We don't use clone as long as we don't inherit Cloneable iface
|
||||||
|
* @note This requires Snake, Apple and Ladder copy constructors
|
||||||
*/
|
*/
|
||||||
Board (Board B) {
|
Board (Board B) {
|
||||||
this.N = B.getN();
|
N = B.getN();
|
||||||
this.M = B.getM();
|
M = B.getM();
|
||||||
tiles = new int[N][M];
|
tiles = new int[N][M];
|
||||||
snakes = new Snake[B.getSnakes().length];
|
snakes = new Snake[B.getSnakes().length];
|
||||||
ladders = new Ladder[B.getLadders().length];
|
ladders = new Ladder[B.getLadders().length];
|
||||||
apples = new Apple[B.getApples().length];
|
apples = new Apple[B.getApples().length];
|
||||||
// Copy B's guts
|
// Copy B's guts into new memory
|
||||||
for (int i =0 ; i<N ; ++i)
|
setTiles(B.getTiles()); // primitive
|
||||||
for (int j =0 ; j<M ; ++j)
|
copySnakes(B.getSnakes());
|
||||||
tiles[i][j] = B.getTiles()[i][j];
|
copyLadders(B.getLadders());
|
||||||
for (int i =0 ; i<B.getSnakes().length ; ++i)
|
copyApples(B.getApples());
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
@ -68,46 +94,27 @@ public class Board {
|
|||||||
|
|
||||||
/** Get value N */
|
/** Get value N */
|
||||||
int getN () { return N; }
|
int getN () { return N; }
|
||||||
/**
|
/** Set value N */
|
||||||
* Set value N
|
void setN (int N) { this.N = 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 */
|
/** Get value M */
|
||||||
int getM () { return M; }
|
int getM () { return M; }
|
||||||
/**
|
/** Set value M */
|
||||||
* Set value M
|
void setM (int M) { this.M = 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 */
|
/** Get reference to tiles */
|
||||||
int[][] getTiles () { return tiles; }
|
int[][] getTiles () { return tiles; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set tiles (deep copy)
|
* Set tiles
|
||||||
* @param tiles Source of tiles to use
|
* @param tiles Source of tiles to use
|
||||||
* @throws BadBoardInput
|
* @note This has to be called if the board is default constructed
|
||||||
*/
|
*/
|
||||||
void setTiles (int[][] tiles) throws BadBoardInput {
|
void setTiles (int[][] tiles) {
|
||||||
// Input checking
|
|
||||||
if (tiles.length != N && tiles[0].length != M)
|
|
||||||
throw new BadBoardInput("tiles size missmatch");
|
|
||||||
// Check if we need allocation
|
// Check if we need allocation
|
||||||
if (this.tiles == null)
|
if (this.tiles == null)
|
||||||
this.tiles = new int[N][M];
|
this.tiles = new int[N][M];
|
||||||
// Assign values (deep copy)
|
// Assign values
|
||||||
for (int i =0 ; i<N ; ++i)
|
for (int i =0 ; i<N ; ++i)
|
||||||
for (int j =0 ; j<M ; ++j)
|
for (int j =0 ; j<M ; ++j)
|
||||||
this.tiles[i][j] = tiles[i][j];
|
this.tiles[i][j] = tiles[i][j];
|
||||||
@ -116,58 +123,68 @@ public class Board {
|
|||||||
/** Get reference to snakes */
|
/** Get reference to snakes */
|
||||||
Snake[] getSnakes() { return snakes; }
|
Snake[] getSnakes() { return snakes; }
|
||||||
/**
|
/**
|
||||||
* Set snakes (deep copy)
|
* Set snakes
|
||||||
* @param snakes Source of snakes to use
|
* @param snakes Reference to snakes to use
|
||||||
* @throws BadBoardInput
|
* @note This requires snakes must be allocated elsewhere.
|
||||||
* @note Requires Snake copy contructor
|
|
||||||
*/
|
*/
|
||||||
void setSnakes(Snake[] snakes) throws BadBoardInput {
|
void setSnakes(Snake[] snakes) { this.snakes = snakes; }
|
||||||
// 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 */
|
/** Get reference to ladders */
|
||||||
Ladder[] getLadders() { return ladders; }
|
Ladder[] getLadders() { return ladders; }
|
||||||
/**
|
/**
|
||||||
* Set ladders (deep copy)
|
* Set ladders
|
||||||
* @param ladders Source of snakes to use
|
* @param ladders Reference to ladders to use
|
||||||
* @throws BadBoardInput
|
* @note This requires ladders must be allocated elsewhere.
|
||||||
* @note Requires Ladder copy contructor
|
|
||||||
*/
|
*/
|
||||||
void setLadders (Ladder[] ladders) throws BadBoardInput {
|
void setLadders(Ladder[] ladders) { this.ladders = ladders; }
|
||||||
// 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 */
|
/** Get reference to apples */
|
||||||
Apple[] getApples() { return apples; }
|
Apple[] getApples() { return apples; }
|
||||||
/**
|
/**
|
||||||
* Set apples (deep copy)
|
* Set apples
|
||||||
* @param apples Source of snakes to use
|
* @param apples Reference to apples to use
|
||||||
* @throws BadBoardInput
|
* @note This requires apples must be allocated elsewhere.
|
||||||
* @note Requires Apple copy contructor
|
|
||||||
*/
|
*/
|
||||||
void setApples (Apple[] apples) throws BadBoardInput {
|
void setApples(Apple[] apples) { this.apples = apples; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy snakes (deep copy)
|
||||||
|
* @param snakes Source of snakes to use
|
||||||
|
* @note Requires Snake copy constructor
|
||||||
|
* @note This has to be called if the board is default constructed
|
||||||
|
*/
|
||||||
|
void copySnakes(Snake[] snakes) {
|
||||||
|
// Check if we need allocation
|
||||||
|
if (this.snakes == null)
|
||||||
|
this.snakes = new Snake[snakes.length];
|
||||||
|
// Assign values (deep copy)
|
||||||
|
for (int i =0 ; i<this.snakes.length ; ++i)
|
||||||
|
this.snakes[i] = new Snake(snakes[i]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copy ladders (deep copy)
|
||||||
|
* @param ladders Source of ladders to use
|
||||||
|
* @note Requires Ladder copy constructor
|
||||||
|
* @note This has to be called if the board is default constructed
|
||||||
|
*/
|
||||||
|
void copyLadders (Ladder[] ladders) {
|
||||||
|
// Check if we need allocation
|
||||||
|
if (this.ladders == null)
|
||||||
|
this.ladders = new Ladder[ladders.length];
|
||||||
|
// Assign values (deep copy)
|
||||||
|
for (int i =0 ; i<this.ladders.length ; ++i)
|
||||||
|
this.ladders[i] = new Ladder(ladders[i]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copy apples (deep copy)
|
||||||
|
* @param apples Source of apples to use
|
||||||
|
* @note Requires Apple copy constructor
|
||||||
|
* @note This has to be called if the board is default constructed
|
||||||
|
*/
|
||||||
|
void copyApples (Apple[] apples) {
|
||||||
// Check if we need allocation
|
// Check if we need allocation
|
||||||
if (this.apples == null)
|
if (this.apples == null)
|
||||||
this.apples = new Apple[apples.length];
|
this.apples = new Apple[apples.length];
|
||||||
// Input checking
|
|
||||||
if (this.apples.length != apples.length)
|
|
||||||
throw new BadBoardInput("ladders size missmatch");
|
|
||||||
// Assign values (deep copy)
|
// Assign values (deep copy)
|
||||||
for (int i =0 ; i<this.apples.length ; ++i)
|
for (int i =0 ; i<this.apples.length ; ++i)
|
||||||
this.apples[i] = new Apple(apples[i]);
|
this.apples[i] = new Apple(apples[i]);
|
||||||
@ -177,19 +194,76 @@ public class Board {
|
|||||||
/** @name Exposed API members */
|
/** @name Exposed API members */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a playable board for the game
|
* Check if the tile is a snake head. If so return the snake's
|
||||||
|
* tails tile. If not return the same tile
|
||||||
|
* @param tile The tile to check
|
||||||
|
* @return The result tile
|
||||||
*/
|
*/
|
||||||
void createBoard () {
|
int checkSnake (int tile) {
|
||||||
_tile_numbering (); // Create tile numbering
|
for (int i =0 ; i<snakes.length ; ++i) {
|
||||||
_place_snakes (); // Place snakes
|
if (snakes[i].getHeadId() == tile)
|
||||||
_place_apples (); // Place Apples
|
return snakes[i].getTailId();
|
||||||
_place_ladders (); // place ladders
|
}
|
||||||
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* make and PRINT element boards
|
* Check if the tile is a ladder down step. If so return the ladder's
|
||||||
|
* up step tile. If not return the same tile.
|
||||||
|
* @note
|
||||||
|
* This also break the ladder if used
|
||||||
|
* @param tile The tile to check
|
||||||
|
* @return The result tile
|
||||||
|
*/
|
||||||
|
int checkLadder (int tile) {
|
||||||
|
for (int i =0 ; i<ladders.length ; ++i) {
|
||||||
|
if (ladders[i].getDownStepId() == tile &&
|
||||||
|
ladders[i].getBroken() == false) {
|
||||||
|
ladders[i].setBroken(true);
|
||||||
|
return ladders[i].getUpStepId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the tile is an apple tile. If so eat it and return the score difference
|
||||||
|
* @param tile The tile to check
|
||||||
|
* @return The score difference
|
||||||
|
*/
|
||||||
|
int checkApple (int tile) {
|
||||||
|
int ds =0; // delta-score
|
||||||
|
for (int i =0 ; i<apples.length ; ++i) {
|
||||||
|
if (apples[i].getAppleTileId() == tile) {
|
||||||
|
// eat it
|
||||||
|
ds = apples[i].getPoints();
|
||||||
|
apples[i].setPoints(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a playable board for the game.
|
||||||
|
* @warning
|
||||||
|
* This is not required to be called after construction in order to ensure board's playable
|
||||||
|
* condition. In fact this function SHOULD NOT CALLED AT ALL.
|
||||||
|
* The project requirements expect this to be public. The preferable mode would be private.
|
||||||
|
* @see Board() constructor.
|
||||||
|
*/
|
||||||
|
void createBoard () {
|
||||||
|
_tileNumbering (); // Create tile numbering
|
||||||
|
_placeSnakes (); // Place snakes
|
||||||
|
_placeApples (); // Place Apples
|
||||||
|
_placeLadders (); // place ladders
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* make and print element boards
|
||||||
|
* This is not required in order for the board to be playable
|
||||||
|
* It just produce a stdout output for convenience.
|
||||||
*/
|
*/
|
||||||
void createElementBoard () {
|
void createElementBoard () {
|
||||||
String[][] elementBoardSnakes = new String[N][M];
|
String[][] elementBoardSnakes = new String[N][M];
|
||||||
@ -212,11 +286,11 @@ public class Board {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Create the tile numbering
|
* Create the tile numbering in a boustrophedon (zig-zag) way.
|
||||||
* We use a starting point the tile[0][0] and as finish point
|
* We use a starting point the tile[0][0] and as finish point
|
||||||
* the tile[N-1][M-1]
|
* the tile[N-1][M-1]
|
||||||
*/
|
*/
|
||||||
private void _tile_numbering () {
|
private void _tileNumbering () {
|
||||||
for (int i=0, tile =1 ; i<N ; ++i) {
|
for (int i=0, tile =1 ; i<N ; ++i) {
|
||||||
if (i%2 == 0) {
|
if (i%2 == 0) {
|
||||||
// Even row, go right
|
// Even row, go right
|
||||||
@ -234,32 +308,33 @@ public class Board {
|
|||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Place the snakes on the board
|
* Place the snakes on the board
|
||||||
* The only constrain at this point is that snake tails must be
|
* The only constrain at this point is that snake tails must be placed
|
||||||
* below heads and in different tiles
|
* below heads and heads must be placed in separate tiles
|
||||||
*/
|
*/
|
||||||
private void _place_snakes () {
|
private void _placeSnakes () {
|
||||||
int [] head = new int [snakes.length]; // temporary place holder for heads
|
int [] head = new int [snakes.length]; // temporary place holder for heads
|
||||||
int [] tail = new int [snakes.length]; // temporary place holder for tails
|
int [] tail = new int [snakes.length]; // temporary place holder for tails
|
||||||
for (int i =0, tile =0 ; i<snakes.length ; ++i) {
|
for (int i =0, tile =0 ; i<snakes.length ; ++i) {
|
||||||
// Keep getting heads until they are different from the previous
|
// Keep getting heads until they are different from the previous
|
||||||
do
|
do
|
||||||
tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
|
tile = _pickRandom (M+1, M*N); // Don't use first row for heads
|
||||||
while (_search (head, tile) >= 0);
|
while (_search (head, tile) >= 0);
|
||||||
head[i] = tile;
|
head[i] = tile;
|
||||||
tail[i] = (int)(Math.random() * (head[i] - head[i]%M)); // Don't use heads row and up for tail
|
tail[i] = _pickRandom (1, 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
|
snakes[i] = new Snake(i, head[i], tail[i]); // Allocate snake
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Place apples on the board
|
* Place apples on the board
|
||||||
* At this point we have snakes. The constrains here are
|
* The constrains here are
|
||||||
* that apples have to lie on different tiles and not in some
|
* that apples have to lie on different tiles and not in some
|
||||||
* snake's head
|
* snake's head.
|
||||||
|
* @note We require we have snakes.
|
||||||
*/
|
*/
|
||||||
private void _place_apples () {
|
private void _placeApples () {
|
||||||
int [] apple_tiles = new int [apples.length]; // temporary placeholder for heads
|
int [] apple_tiles = new int [apples.length]; // temporary placeholder for apples
|
||||||
int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
|
int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
|
||||||
for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
|
for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
|
||||||
snake_tiles[i] = snakes[i].getHeadId();
|
snake_tiles[i] = snakes[i].getHeadId();
|
||||||
@ -268,11 +343,12 @@ public class Board {
|
|||||||
// Keep getting tiles until they are different from the previous
|
// Keep getting tiles until they are different from the previous
|
||||||
// and not in some snake's head
|
// and not in some snake's head
|
||||||
do
|
do
|
||||||
tile = (int) (Math.random() * (N * M));
|
tile = _pickRandom (1, M*N);
|
||||||
while ((_search (apple_tiles, tile) >= 0) ||
|
while ((_search (apple_tiles, tile) >= 0) ||
|
||||||
(_search (snake_tiles, tile) >= 0));
|
(_search (snake_tiles, tile) >= 0));
|
||||||
apple_tiles[i] = tile;
|
apple_tiles[i] = tile;
|
||||||
int points = (int)(Math.random() *10) * 5; // get points
|
// get points
|
||||||
|
int points = _pickRandom (1, (POINTS_MAX/POINTS_STEP)) * POINTS_STEP;
|
||||||
boolean red = (boolean)(Math.random() >=0.5); // get color
|
boolean red = (boolean)(Math.random() >=0.5); // get color
|
||||||
// Allocate apple
|
// Allocate apple
|
||||||
if (red)
|
if (red)
|
||||||
@ -285,34 +361,49 @@ public class Board {
|
|||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Place ladders on board
|
* Place ladders on board
|
||||||
* At this point we have snakes and apples.
|
*
|
||||||
* @note
|
* We add constrains so each ladder's up-step tile has to be different from:
|
||||||
* We add a constrain for ladder so its up-setp has to be different from a
|
* * A snake's head tile. This ensures ladders and snakes are independent
|
||||||
* snake's head tile. This ensures the each ladder and snake are independent
|
* * A ladders's down-step. This ensure we eliminate ladder chains.
|
||||||
|
* * One other ladder's up-step. This is not critical but helps the printElement functionality
|
||||||
|
*
|
||||||
|
* We add constrains so each ladder's down-step tile has to be different from:
|
||||||
|
* * A snake's head tile. This ensures ladders and snakes are independent
|
||||||
|
* * A ladders's down-step. This is not critical but helps the printElement functionality
|
||||||
|
* * One other ladder's up-step. This ensure we eliminate ladder chains.
|
||||||
|
* @note We require we have snakes.
|
||||||
*/
|
*/
|
||||||
private void _place_ladders () {
|
private void _placeLadders () {
|
||||||
int [] upstep = new int [ladders.length]; // temporary place holder for up-steps
|
int [] up_step = new int [ladders.length]; // temporary place holder for up-steps
|
||||||
int [] downstep = new int [ladders.length]; // temporary place holder for down-step
|
int [] down_step = new int [ladders.length]; // temporary place holder for down-step
|
||||||
int [] snake_tiles = new int [snakes.length]; // array with snake head tiles
|
int [] snake_tiles= new int [snakes.length]; // array with snake head tiles
|
||||||
for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
|
for (int i =0 ; i<snakes.length ; ++i) // Load snake head tiles
|
||||||
snake_tiles[i] = snakes[i].getHeadId();
|
snake_tiles[i] = snakes[i].getHeadId();
|
||||||
|
|
||||||
for (int i =0, tile =0 ; i<ladders.length ; ++i) {
|
for (int i =0, tile =0 ; i<ladders.length ; ++i) {
|
||||||
// Keep getting up-steps until they are different from the previous
|
// Keep getting up-steps until they are different from the previous ladder tiles
|
||||||
// and not in some snake's head
|
// and not in some snake's head
|
||||||
do
|
do
|
||||||
tile = (int)(M + Math.random() * (N-1) * M); // Don't use first row for heads
|
tile = _pickRandom (M+1, M*N); // Don't use first row for up-steps
|
||||||
while ((_search (upstep, tile) >= 0) ||
|
while ((_search (up_step, tile) >= 0)
|
||||||
(_search (snake_tiles, tile) >= 0));
|
|| (_search (down_step, tile) >= 0)
|
||||||
upstep[i] = tile;
|
|| (_search (snake_tiles, tile) >= 0));
|
||||||
downstep[i] = (int)(Math.random() * (upstep[i] - upstep[i]%M));
|
up_step[i] = tile;
|
||||||
//^ Don't use up-step row and up for down-step
|
// Keep getting down-steps until they are different from the previous ladder tiles
|
||||||
ladders[i] = new Ladder (i, upstep[i], downstep[i]); // Allocate ladder
|
// and not in some snake's head
|
||||||
|
do
|
||||||
|
// Don't use up-step row and up for down-step
|
||||||
|
tile = _pickRandom (1, up_step[i]-up_step[i]%M);
|
||||||
|
while ((_search (up_step, tile) >= 0)
|
||||||
|
|| (_search (down_step, tile) >= 0)
|
||||||
|
|| (_search (snake_tiles, tile) >= 0));
|
||||||
|
down_step[i] = tile;
|
||||||
|
ladders[i] = new Ladder (i, up_step[i], down_step[i]); // Allocate ladder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make element array of snakes
|
* Make element array of snakes as required by the project
|
||||||
* @param elemSnakes
|
* @param elemSnakes
|
||||||
*/
|
*/
|
||||||
private void _makeElementSnakes (String[][] elemSnakes) {
|
private void _makeElementSnakes (String[][] elemSnakes) {
|
||||||
@ -339,7 +430,7 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make element array of ladders
|
* Make element array of ladders as required by the project
|
||||||
* @param elemLadders
|
* @param elemLadders
|
||||||
*/
|
*/
|
||||||
private void _makeElementLadders (String[][] elemLadders) {
|
private void _makeElementLadders (String[][] elemLadders) {
|
||||||
@ -366,7 +457,7 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make element array of apples
|
* Make element array of apples as required by the project
|
||||||
* @param elemApples
|
* @param elemApples
|
||||||
*/
|
*/
|
||||||
private void _makeElementApples (String[][] elemApples) {
|
private void _makeElementApples (String[][] elemApples) {
|
||||||
@ -401,10 +492,12 @@ public class Board {
|
|||||||
* @note
|
* @note
|
||||||
* As long as we use tiles[0][0] for first tile, this method
|
* As long as we use tiles[0][0] for first tile, this method
|
||||||
* has to print in reverse Y-axis order. For ex:
|
* has to print in reverse Y-axis order. For ex:
|
||||||
|
* <pre>
|
||||||
* 16 15 14 13
|
* 16 15 14 13
|
||||||
* 09 10 11 12
|
* 09 10 11 12
|
||||||
* 08 07 06 05
|
* 08 07 06 05
|
||||||
* 01 02 03 04
|
* 01 02 03 04
|
||||||
|
* </pre>
|
||||||
*/
|
*/
|
||||||
private void _printElement (String[][] elem, String caption) {
|
private void _printElement (String[][] elem, String caption) {
|
||||||
System.out.print(caption);
|
System.out.print(caption);
|
||||||
@ -418,6 +511,16 @@ public class Board {
|
|||||||
System.out.println("");
|
System.out.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick a random tile in range [from..to]
|
||||||
|
* @param from The first tile to consider
|
||||||
|
* @param to The last tile to consider
|
||||||
|
* @return The random pick
|
||||||
|
*/
|
||||||
|
private int _pickRandom (int from, int to) {
|
||||||
|
return from + (int)(Math.random() * (to - from));
|
||||||
|
}
|
||||||
|
|
||||||
/** Search algorithm
|
/** Search algorithm
|
||||||
* @param array Array to search
|
* @param array Array to search
|
||||||
* @param elem Element of type T to find inside of array
|
* @param elem Element of type T to find inside of array
|
||||||
@ -433,19 +536,14 @@ public class Board {
|
|||||||
}
|
}
|
||||||
/**@} */
|
/**@} */
|
||||||
|
|
||||||
/** @name Data members (private) */
|
/** @name Data members */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
private int N; //!< Board's row count
|
private int N; /**< Board's row count */
|
||||||
private int M; //!< Board's Column count
|
private int M; /**< Board's Column count */
|
||||||
private int[][] tiles; //!< Board's tiles
|
private int[][] tiles; /**< Board's tiles */
|
||||||
private Snake[] snakes; //!< Board's snakes
|
private Snake[] snakes; /**< Board's snakes */
|
||||||
private Ladder[] ladders; //!< Board's ladders
|
private Ladder[] ladders; /**< Board's ladders */
|
||||||
private Apple[] apples; //!< Board's apples
|
private Apple[] apples; /**< Board's apples */
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
}
|
||||||
|
|
||||||
class BadBoardInput extends Exception {
|
|
||||||
BadBoardInput() {}
|
|
||||||
BadBoardInput(String str) { super(str); }
|
|
||||||
//static final long SerialVersionUIDAdder = 0;
|
|
||||||
}
|
|
||||||
|
@ -1,17 +1,210 @@
|
|||||||
package SnakePkg;
|
package SnakePkg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mainpage
|
||||||
|
* @title Snake game project. -- Part 1 --
|
||||||
|
*
|
||||||
|
* This is the code documentation page of the Snake game project.
|
||||||
|
* Listed are:
|
||||||
|
* * All used classes
|
||||||
|
* * All member functions
|
||||||
|
* * All data members
|
||||||
|
*
|
||||||
|
* @author Christos Choutouridis 8997
|
||||||
|
* @email cchoutou@ece.auth.gr
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.Math;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Game
|
||||||
|
*
|
||||||
|
* @brief This is the main control class of the game.
|
||||||
|
*
|
||||||
|
* This class includes the main function.Using this class's api
|
||||||
|
* the user can create a board, register players and roll the game.
|
||||||
|
*
|
||||||
|
* @author Christos Choutouridis 8997
|
||||||
|
* @email cchoutou@ece.auth.gr
|
||||||
|
*/
|
||||||
public class Game {
|
public class Game {
|
||||||
|
/** Constants */
|
||||||
|
/**@{ */
|
||||||
|
static final int MAX_PLAYERS = 4; /**< The maximum number of allowed players in the game */
|
||||||
|
/**@} */
|
||||||
|
|
||||||
public static void main(String[] args) {
|
/** Private data members */
|
||||||
try {
|
/** @{ */
|
||||||
Board b = new Board(10, 20, 3, 6, 6);
|
private int round; /**< The current round of the game */
|
||||||
|
private Board board; /**< A reference to board */
|
||||||
|
private ArrayList<Player> players; /**< A reference to players */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
b.createBoard();
|
/** private api */
|
||||||
b.createElementBoard();
|
/** @{ */
|
||||||
}
|
/**
|
||||||
catch(Exception e){
|
* Dice functionality
|
||||||
System.out.println("Exception caught:" + e.getMessage());
|
* @return An integer in the range [1 .. 6]
|
||||||
}
|
*/
|
||||||
|
private int _dice () {
|
||||||
|
return (int)(1 + Math.random()*5);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Search the players already in the players vector and compare their turn to play
|
||||||
|
* with the result of a dice. If there is another one with the same dice result return true.
|
||||||
|
*
|
||||||
|
* @param turn The dice result to check in order to find player's turn to play
|
||||||
|
* @param players Reference to already register players
|
||||||
|
* @return True if there is another player with the same dice result
|
||||||
|
*/
|
||||||
|
private boolean _search (int die, ArrayList<Player> players) {
|
||||||
|
for (int i =0; i<players.size() ; ++i)
|
||||||
|
if (players.get(i).getTurn() == die)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
/** Constructors */
|
||||||
|
/** @{ */
|
||||||
|
/** Default doing nothing constructor */
|
||||||
|
Game () {
|
||||||
|
round = 0;
|
||||||
|
board = new Board();
|
||||||
|
players = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The main constructor
|
||||||
|
* This constructor create a board and prepares the board for the game.
|
||||||
|
* After this call the user can call @ref registerPlayer()
|
||||||
|
* @param N The row for the board
|
||||||
|
* @param M The columns of the board
|
||||||
|
* @param numOfSnakes Number of snakes to place
|
||||||
|
* @param numOfLadders Number of ladders to place
|
||||||
|
* @param numOfApples Number of Apples to place
|
||||||
|
*/
|
||||||
|
Game (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples) {
|
||||||
|
round = 0;
|
||||||
|
// delegate constructors
|
||||||
|
board = new Board (N, M, numOfSnakes, numOfLadders, numOfApples);
|
||||||
|
players = new ArrayList<>();
|
||||||
|
board.createElementBoard(); //Not critical, but placed here as project requirement
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Get/Set interface */
|
||||||
|
/** @{ */
|
||||||
|
int getRound () { return round; }
|
||||||
|
void setRound (int round) { this.round = round; }
|
||||||
|
/** Get reference to board */
|
||||||
|
Board getBoard () { return board; }
|
||||||
|
/** Set board
|
||||||
|
* @param board Reference to board to use
|
||||||
|
* @note This requires board must be allocated elsewhere.
|
||||||
|
*/
|
||||||
|
void setBoard (Board board) {
|
||||||
|
this.board = board;
|
||||||
|
}
|
||||||
|
/** Get reference to players */
|
||||||
|
ArrayList<Player> getPlayers() { return players; }
|
||||||
|
/**
|
||||||
|
* Set players
|
||||||
|
* @param players Reference to players to use
|
||||||
|
* @note This requires players must be allocated elsewhere.
|
||||||
|
*/
|
||||||
|
void setPlayers(ArrayList<Player> players) {
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Public functionality */
|
||||||
|
/** @{ */
|
||||||
|
/**
|
||||||
|
* Register a player to the game
|
||||||
|
* @param playerId The player ID to use
|
||||||
|
* @param name The player name to use
|
||||||
|
* @return The status of the operation
|
||||||
|
*/
|
||||||
|
boolean registerPlayer (int playerId, String name) {
|
||||||
|
if (players.size() >= MAX_PLAYERS)
|
||||||
|
return false;
|
||||||
|
players.add(new Player(playerId, name, board));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Set the playing order of players
|
||||||
|
* This function emulates the classic roll of dice to decide which player
|
||||||
|
* plays first which second and so on.
|
||||||
|
*/
|
||||||
|
void playOrder () {
|
||||||
|
int d;
|
||||||
|
for (int i =0 ; i<players.size() ; ++i) {
|
||||||
|
do
|
||||||
|
// Keep rolling the dice as the die belongs to another user
|
||||||
|
d = _dice();
|
||||||
|
while (_search (d, players));
|
||||||
|
players.get(i).setTurn(d);
|
||||||
|
}
|
||||||
|
// Sort players vector
|
||||||
|
players.sort((p1, p2) -> Integer.compare(p1.getTurn(), p2.getTurn()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A game round. In each round every player plays when is its turn
|
||||||
|
*
|
||||||
|
* @return The winner if we have one, or null
|
||||||
|
*/
|
||||||
|
Player round () {
|
||||||
|
int [] mret;
|
||||||
|
++round; // keep track of round
|
||||||
|
|
||||||
|
// traverse the players vector and move each player on the board
|
||||||
|
// using a dice throw
|
||||||
|
for (int i =0 ; i<players.size() ; ++i) {
|
||||||
|
mret = players.get(i).move (players.get(i).getTile(), _dice());
|
||||||
|
if (mret[0]>= board.getN()*board.getM())
|
||||||
|
// The first one here is the winner
|
||||||
|
return players.get(i);
|
||||||
|
}
|
||||||
|
return null; // No one finished yet
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main
|
||||||
|
* As the requirements of the project suggested.
|
||||||
|
* We:
|
||||||
|
* * Create a game
|
||||||
|
* * Manually create a board
|
||||||
|
* * Register 2 players (John Doe for now)
|
||||||
|
* * Place a predefined number of snakes, ladders and apples
|
||||||
|
* * Deploy the game by calling @ref playOrder() and @ref round()
|
||||||
|
* At the end we print the results and exit
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Game game = new Game(20, 10, 3, 3, 6); // Board creation
|
||||||
|
|
||||||
|
game.registerPlayer(1, "Player 1"); // Player registration
|
||||||
|
game.registerPlayer(2, "Player 2");
|
||||||
|
game.playOrder(); // Choose play order
|
||||||
|
|
||||||
|
Player winner;
|
||||||
|
do // Keep going until someone finishes
|
||||||
|
winner = game.round ();
|
||||||
|
while (winner == null);
|
||||||
|
|
||||||
|
// Print the results
|
||||||
|
System.out.println("Game finished.");
|
||||||
|
System.out.println("Rounds played: " + game.getRound());
|
||||||
|
System.out.println("Winner: " + winner.getName() + ". Score: " + winner.getScore());
|
||||||
|
for (int i=0 ; i<game.getPlayers().size() ; ++i) {
|
||||||
|
// Loop all the non-winning players
|
||||||
|
Player p = game.getPlayers().get(i);
|
||||||
|
if (p != winner)
|
||||||
|
System.out.println(p.getName() + ". Score: " + p.getScore());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user