Browse Source

Init commit

tags/v1.0
Christos Houtouridis 5 years ago
commit
626ef9b880
6 changed files with 659 additions and 0 deletions
  1. +5
    -0
      .gitignore
  2. +88
    -0
      src/SnakePkg/Apple.java
  3. +451
    -0
      src/SnakePkg/Board.java
  4. +17
    -0
      src/SnakePkg/Game.java
  5. +52
    -0
      src/SnakePkg/Ladder.java
  6. +46
    -0
      src/SnakePkg/Snake.java

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
*bin/*
*.project
*.classpath
*.pdf


+ 88
- 0
src/SnakePkg/Apple.java View File

@@ -0,0 +1,88 @@
package SnakePkg;
import java.lang.Math;
/**
* A class to represent an Apple in the Board
* @author Christos Choutouridis 8997
*/
public class Apple {
/** @name Constructors */
/** @{ */
/** Default ctor */
Apple () {
appleId = appleTileId= 0;
color = "";
points = 0;
}
/** Main ctor */
Apple (int appleId, int appleTileId, String color, int points) {
this.appleId = appleId;
this.appleTileId = appleTileId;
this.color = color;
this.points = points;
}
/** Copy constructor
* @note We don't use clone as long as we don't inherit Cloneable iface
*/
Apple (Apple a) {
appleId = a.getAppleId ();
appleTileId = a.getAppleTileId ();
color = a.getColor ();
points = a.getPoints ();
}
/** @} */
/** @name Get/Set interface */
/** @{ */
int getAppleId () { return appleId; }
void setAppleId (int appleId) { this.appleId = appleId; }
int getAppleTileId () { return appleTileId; }
void setAppleTileId (int appleTileId) { this.appleTileId = appleTileId; }
String getColor () { return color; }
/**
* We set color and we update points sign.
* @param color The desired color
* @arg "red" Set color red and mark "points" positive
* @arg "black" Set color black and mark "points" negative
* @arg Otherwise zero
*/
void setColor (String color) {
this.color = color;
if (color == "red") points = Math.abs(points);
else if (color == "black") points = -Math.abs(points);
else points = 0;
}
int getPoints () { return points; }
/** We set the points and update its sign based on color */
void setPoints (int points) {
if (color == "red") this.points = Math.abs(points);
else this.points = -Math.abs(points);
}
/** @} */
/** @name Data members (private) */
/** @{ */
private int appleId; //!< Apples's ID
private int appleTileId; //!< Apple's tile location
private String color; //!< Apple's color
/**^
* @note
* This way of representing color is not preferable by the author.
* An enum Color { red, black } would be better and far less error prone
* In order to support this style we have to strict the color names to
* lower case letters. We also update the points sign to make thinks easier.
* @see setColor
*/
private int points; //!< The points added (algebraically) to the user
/** @} */
}
//class BadColor extends Exception {
// // default constructor
// BadColor() { }
// // parametrized constructor
// BadColor (String str) { super(str); }
//}

+ 451
- 0
src/SnakePkg/Board.java View File

@@ -0,0 +1,451 @@
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;
}

+ 17
- 0
src/SnakePkg/Game.java View File

@@ -0,0 +1,17 @@
package SnakePkg;
public class Game {
public static void main(String[] args) {
try {
Board b = new Board(10, 20, 3, 6, 6);
b.createBoard();
b.createElementBoard();
}
catch(Exception e){
System.out.println("Exception caught:" + e.getMessage());
}
}
}

+ 52
- 0
src/SnakePkg/Ladder.java View File

@@ -0,0 +1,52 @@
package SnakePkg;
/**
* A class to represent a Ladder in the Board
* @author Christos Choutouridis 8997
*/
public class Ladder {
/** @name Constructors */
/** @{ */
/** Default ctor */
Ladder () {
ladderId = upStepId = downStepId =0;
broken = false;
}
/** Main ctor */
Ladder (int ladderId, int upStepId, int downStepId) {
this.ladderId = ladderId;
this.upStepId = upStepId;
this.downStepId = downStepId;
this.broken = false; // A new ladder is always in good condition
}
/** Copy constructor
* @note We don't use clone as long as we don't inherit Cloneable iface
*/
Ladder (Ladder l) {
ladderId = l.getLadderId ();
upStepId = l.getUpStepId ();
downStepId = l.getDownStepId ();
broken = l.getBroken ();
}
/** @} */
/** @name Get/Set interface */
/** @{ */
int getLadderId () { return ladderId; }
void setLadderId (int ladderId) { this.ladderId = ladderId; }
int getUpStepId () { return upStepId; }
void setUpStepId (int upStepId) { this.upStepId = upStepId; }
int getDownStepId () { return downStepId; }
void setDownStepId (int downStepId) { this.downStepId = downStepId; }
boolean getBroken () { return broken; }
void setBroken (boolean broken) { this.broken = broken; }
/** @} */
/** @name Data members (private) */
/** @{ */
private int ladderId; //!< Ladder's ID
private int upStepId; //!< Ladder's upper step tile location
private int downStepId; //!< Snake's down step tile location
private boolean broken; //!< flag to indicate used/broken ladder
/** @} */
}

+ 46
- 0
src/SnakePkg/Snake.java View File

@@ -0,0 +1,46 @@
package SnakePkg;
/**
* A class to represent a Snake in the Board
* @author Christos Choutouridis 8997
*/
public class Snake {
/** @name Constructors */
/** @{ */
/** Default ctor */
Snake () {
snakeId = headId = tailId = 0;
}
/** Main Constructor */
Snake (int snakeId, int headId, int tailId) {
this.snakeId = snakeId;
this.headId = headId;
this.tailId = tailId;
}
/** Copy constructor
* @note We don't use clone as long as we don't inherit Cloneable iface
*/
Snake (Snake s) {
snakeId = s.getSnakeId ();
headId = s.getHeadId ();
tailId = s.getTailId ();
}
/** @} */
/** @name Get/Set interface */
/** @{ */
int getSnakeId () { return snakeId; }
void setSnakeId (int snakeId) { this.snakeId = snakeId; }
int getHeadId () { return headId; }
void setHeadId (int headId) { this.headId = headId; }
int getTailId () { return tailId; }
void setTailId (int tailId) { this.tailId = tailId; }
/** @} */
/** @name Data members (private) */
/** @{ */
private int snakeId; //!< Snake's ID
private int headId; //!< Snake's head tile location
private int tailId; //!< Snake's tail tile location
/** @} */
}

Loading…
Cancel
Save