diff --git a/src/SnakePkg/Board.java b/src/SnakePkg/Board.java index 1758f7e..7396fd7 100755 --- a/src/SnakePkg/Board.java +++ b/src/SnakePkg/Board.java @@ -1,15 +1,32 @@ 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 + * @email cchoutou@ece.auth.gr */ 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 */ /** @{ */ - /** 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 () { N = M =0; tiles = null; @@ -19,47 +36,56 @@ public class Board { } /** - * Main constructor - * We make some simple input checking before memory allocation. - * @note - * May throw BadBoardInput + * @brief Creates a board for game + * + * This constructor allocates the memory for the board and elements and + * 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) - throws BadBoardInput { - // Input checking - if (numOfApples + numOfLadders*2 + numOfSnakes*2 >= N*M/2) - throw new BadBoardInput("Too many Apples, Snakes and ladders"); + Board (int N, int M, int numOfSnakes, int numOfLadders, int numOfApples) { // Init the board object - setN (N); // Input checked version (may throw) - setM (M); // Input checked version (may throw) + 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]; + 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 - * data to be valid + * @brief Copy constructor. + * 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 This requires Snake, Apple and Ladder copy constructors */ Board (Board B) { - this.N = B.getN(); - this.M = B.getM(); + N = B.getN(); + 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= 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 + 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 } } /** * @brief * 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 - * snake's head + * snake's head. + * @note We require we have snakes. */ - private void _place_apples () { - int [] apple_tiles = new int [apples.length]; // temporary placeholder for heads + private void _placeApples () { + int [] apple_tiles = new int [apples.length]; // temporary placeholder for apples int [] snake_tiles = new int [snakes.length]; // array with snake head tiles for (int i =0 ; i= 0) || (_search (snake_tiles, tile) >= 0)); 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 // Allocate apple if (red) @@ -285,34 +361,49 @@ public class Board { /** * @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 + * + * We add constrains so each ladder's up-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 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 () { - 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 + private void _placeLadders () { + int [] up_step = new int [ladders.length]; // temporary place holder for up-steps + 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 for (int i =0 ; i= 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 + tile = _pickRandom (M+1, M*N); // Don't use first row for up-steps + while ((_search (up_step, tile) >= 0) + || (_search (down_step, tile) >= 0) + || (_search (snake_tiles, tile) >= 0)); + up_step[i] = tile; + // Keep getting down-steps until they are different from the previous ladder tiles + // 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 */ 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 */ 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 */ private void _makeElementApples (String[][] elemApples) { @@ -401,10 +492,12 @@ public class Board { * @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); @@ -418,6 +511,16 @@ public class Board { 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 * @param array Array to search * @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 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 + 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; -} diff --git a/src/SnakePkg/Game.java b/src/SnakePkg/Game.java index a735347..cc3d596 100644 --- a/src/SnakePkg/Game.java +++ b/src/SnakePkg/Game.java @@ -1,17 +1,210 @@ 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 { + /** Constants */ + /**@{ */ + static final int MAX_PLAYERS = 4; /**< The maximum number of allowed players in the game */ + /**@} */ + + /** Private data members */ + /** @{ */ + private int round; /**< The current round of the game */ + private Board board; /**< A reference to board */ + private ArrayList players; /**< A reference to players */ + /** @} */ - public static void main(String[] args) { - try { - Board b = new Board(10, 20, 3, 6, 6); - - b.createBoard(); - b.createElementBoard(); + /** private api */ + /** @{ */ + /** + * Dice functionality + * @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 players) { + for (int i =0; i(); + } + + /** + * @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 getPlayers() { return players; } + /** + * Set players + * @param players Reference to players to use + * @note This requires players must be allocated elsewhere. + */ + void setPlayers(ArrayList 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 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= 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