Browse Source

A first version of the new structure

tags/v2.0
Christos Houtouridis 6 years ago
parent
commit
4b3a936391
4 changed files with 285 additions and 85 deletions
  1. +6
    -5
      src/net/hoo2/auth/dsproject/snake/Board.java
  2. +101
    -40
      src/net/hoo2/auth/dsproject/snake/Game.java
  3. +80
    -0
      src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java
  4. +98
    -40
      src/net/hoo2/auth/dsproject/snake/Player.java

+ 6
- 5
src/net/hoo2/auth/dsproject/snake/Board.java View File

@@ -223,11 +223,11 @@ public class Board {
* @param tile The tile to check * @param tile The tile to check
* @return The result tile * @return The result tile
*/ */
int checkLadder (int tile) {
int checkLadder (int tile, boolean climb) {
for (int i =0 ; i<ladders.length ; ++i) { for (int i =0 ; i<ladders.length ; ++i) {
if (ladders[i].getDownStepId() == tile && if (ladders[i].getDownStepId() == tile &&
ladders[i].getBroken() == false) { ladders[i].getBroken() == false) {
ladders[i].setBroken(true);
ladders[i].setBroken(climb);
return ladders[i].getUpStepId(); return ladders[i].getUpStepId();
} }
} }
@@ -239,13 +239,14 @@ public class Board {
* @param tile The tile to check * @param tile The tile to check
* @return The score difference * @return The score difference
*/ */
int checkApple (int tile) {
int checkApple (int tile, boolean eat) {
int ds =0; // delta-score int ds =0; // delta-score
for (int i =0 ; i<apples.length ; ++i) { for (int i =0 ; i<apples.length ; ++i) {
if (apples[i].getAppleTileId() == tile) { if (apples[i].getAppleTileId() == tile) {
// eat it
ds = apples[i].getPoints(); ds = apples[i].getPoints();
apples[i].setPoints(0);
// eat it
if (eat)
apples[i].setPoints(0);
} }
} }
return ds; return ds;


+ 101
- 40
src/net/hoo2/auth/dsproject/snake/Game.java View File

@@ -13,9 +13,7 @@ package net.hoo2.auth.dsproject.snake;
* @author Christos Choutouridis AEM:8997 * @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr * @email cchoutou@ece.auth.gr
*/ */
import java.lang.Math;
import java.util.ArrayList;
import java.util.*;
/** /**
* @class Game * @class Game
@@ -31,26 +29,21 @@ import java.util.ArrayList;
public class Game { public class Game {
/** @name Constants */ /** @name Constants */
/**@{ */ /**@{ */
static final int MAX_PLAYERS = 4; /**< The maximum number of allowed players in the game */
static final int MAX_GAME_ROUNDS = 10000; /**< the maximum allowed round of the game */
static final int MAX_PLAYERS = 6; /**< The maximum number of allowed players in the game */
static final int MAX_GAME_ROUNDS = 1000; /**< the maximum allowed round of the game */
/**@} */ /**@} */
/** @name Private data members */ /** @name Private data members */
/** @{ */ /** @{ */
private int round; /**< The current round of the game */ private int round; /**< The current round of the game */
private Board board; /**< A reference to board */ private Board board; /**< A reference to board */
private ArrayList<Player> players; /**< A reference to players */
private ArrayList<Player> players; /**< A reference to players */
private Map<Integer, Integer> playingOrder;
/** @} */ /** @} */
/** @name private api */ /** @name 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 * 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. * with the result of a dice. If there is another one with the same dice result return true.
@@ -59,12 +52,33 @@ public class Game {
* @param players Reference to already register players * @param players Reference to already register players
* @return True if there is another player with the same dice result * @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)
private boolean _search (int die, ArrayList<Integer[]> pairs) {
for (int i =0; i<pairs.size() ; ++i)
if (pairs.get(i)[1] == die)
return true; return true;
return false; return false;
} }
private void _sort (ArrayList<Integer[]> pairs) {
Integer[] temp;
for (int i=pairs.size()-1 ; i>0 ; --i) {
for (int j =0 ; j<i ; ++j) {
if (pairs.get(j)[1] > pairs.get(i)[1]) {
temp = pairs.get(i);
pairs.set(i, pairs.get(j));
pairs.set(j, temp);
}
}
}
}
private Player _getPlayer(int playerId) {
for (Player p : players) {
if (p.getPlayerId() == playerId)
return p;
}
return null;
}
/** @} */ /** @} */
@@ -75,6 +89,8 @@ public class Game {
round = 0; round = 0;
board = new Board(); board = new Board();
players = new ArrayList<>(); players = new ArrayList<>();
playingOrder
= new HashMap<Integer, Integer>();
} }
/** /**
@@ -92,6 +108,8 @@ public class Game {
// delegate constructors // delegate constructors
board = new Board (N, M, numOfSnakes, numOfLadders, numOfApples); board = new Board (N, M, numOfSnakes, numOfLadders, numOfApples);
players = new ArrayList<>(); players = new ArrayList<>();
playingOrder
= new HashMap<Integer, Integer>();
} }
/** @} */ /** @} */
@@ -118,6 +136,11 @@ public class Game {
void setPlayers(ArrayList<Player> players) { void setPlayers(ArrayList<Player> players) {
this.players = players; this.players = players;
} }
Map<Integer, Integer> getPlayingOrder () { return playingOrder; }
void setPlayingOrder (Map<Integer, Integer> playingOrder) {
this.playingOrder = playingOrder;
}
/** @} */ /** @} */
/** @name Public functionality */ /** @name Public functionality */
@@ -134,26 +157,49 @@ public class Game {
players.add(new Player(playerId, name, board)); players.add(new Player(playerId, name, board));
return true; return true;
} }
/**
* 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 registerHeuristicPlayer (int playerId, String name) {
if (players.size() >= MAX_PLAYERS)
return false;
players.add(new HeuristicPlayer(playerId, name, board));
return true;
}
/** /**
* @brief Set the playing order of players * @brief Set the playing order of players
* This function emulates the classic roll of dice to decide which player * This function emulates the classic roll of dice to decide which player
* plays first which second and so on. * plays first which second and so on.
*/ */
void playOrder () {
int d;
for (int i =0 ; i<players.size() ; ++i) {
Map<Integer, Integer> setTurns (ArrayList<Player> players) {
int[] pairData = new int[2];
Integer[] PairData;
ArrayList<Integer[]>
pairList = new ArrayList<>();
for (int d, i =0 ; i<players.size() ; ++i) {
do do
// Keep rolling the dice as the die belongs to another user
d = _dice();
while (_search (d, players));
players.get(i).setTurn(d);
d = players.get(i).dice ();
while (_search (d, pairList));
pairData[0] = players.get(i).getPlayerId();
pairData[1] = d;
PairData = Arrays.stream(pairData).boxed().toArray( Integer[]::new );
pairList.add(PairData);
} }
// Sort players vector
players.sort((p1, p2) ->
Integer.compare (p1.getTurn(), p2.getTurn())
);
// Sort playeingOrger
_sort (pairList);
// Make and return the Map
for (int i =0 ; i<pairList.size() ; ++i) {
playingOrder.put(pairList.get(i)[0], pairList.get(i)[1]);
}
return playingOrder;
} }
/** /**
* Sort the players according to their score * Sort the players according to their score
*/ */
@@ -168,17 +214,19 @@ public class Game {
* *
* @return The winner if we have one, or null * @return The winner if we have one, or null
*/ */
Player round () {
int [] mret;
Player round (boolean verbose) {
int tile;
++round; // keep track of round ++round; // keep track of round
// traverse the players vector and move each player on the board // traverse the players vector and move each player on the board
// using a dice throw // 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())
for (Integer pid : playingOrder.keySet()) {
Player p = _getPlayer(pid);
tile = p.getNextMove (p.getTile());
p.statistics(verbose, false);
if (tile>= board.getN()*board.getM())
// The first one here is the winner // The first one here is the winner
return players.get(i);
return p;
} }
return null; // No one finished yet return null; // No one finished yet
} }
@@ -203,6 +251,7 @@ public class Game {
int numOfLadders = 3; int numOfLadders = 3;
int numOfApples = 6; int numOfApples = 6;
int numOfPlayers = 2; int numOfPlayers = 2;
boolean verbose = false;
// Print caption // Print caption
System.out.println("================== Snake Game =================="); System.out.println("================== Snake Game ==================");
@@ -214,14 +263,18 @@ public class Game {
Game game = new Game (lines, columns, numOfSnakes, numOfLadders, numOfApples); Game game = new Game (lines, columns, numOfSnakes, numOfLadders, numOfApples);
// game.getBoard().createElementBoard(); // Not explicitly required // game.getBoard().createElementBoard(); // Not explicitly required
// Player registration
for (int i=0 ; i<numOfPlayers && i<MAX_PLAYERS; ++i)
game.registerPlayer(i+1, String.format("Player %d", i+1));
game.playOrder(); // Choose play order
// Player registration, the one is cheater
for (int i=0 ; i<numOfPlayers && i<MAX_PLAYERS; ++i) {
if (i == 0)
game.registerHeuristicPlayer(i+1, String.format("Player %d", i+1));
else
game.registerPlayer(i+1, String.format("Player %d", i+1));
}
game.setTurns(game.getPlayers()); // Choose play order
Player winner; Player winner;
do // Keep going until someone finishes do // Keep going until someone finishes
winner = game.round ();
winner = game.round (verbose);
while (winner == null while (winner == null
&& game.getRound() < MAX_GAME_ROUNDS); && game.getRound() < MAX_GAME_ROUNDS);
if (game.getRound() == MAX_GAME_ROUNDS) { if (game.getRound() == MAX_GAME_ROUNDS) {
@@ -231,8 +284,10 @@ public class Game {
} }
// Print the results // Print the results
System.out.println("***** Game finished *****");
System.out.println("*** Game finished ***");
System.out.println(""); System.out.println("");
System.out.println("");
System.out.println("*** Game Results ***");
System.out.println("Rounds: " + game.getRound()); System.out.println("Rounds: " + game.getRound());
System.out.println("Winner: " + winner.getName() + " [" + winner.getScore() +" points]"); System.out.println("Winner: " + winner.getName() + " [" + winner.getScore() +" points]");
System.out.println("Score: "); System.out.println("Score: ");
@@ -245,5 +300,11 @@ public class Game {
else else
System.out.println(" " +p.getName() + ": " + p.getScore() +" points"); System.out.println(" " +p.getName() + ": " + p.getScore() +" points");
} }
for (Player p : game.getPlayers()) {
if (p.getClass().getSimpleName().equals("HeuristicPlayer"))
p.statistics(verbose, true);
}
} }
} }

+ 80
- 0
src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java View File

@@ -0,0 +1,80 @@
package net.hoo2.auth.dsproject.snake;
import java.util.*;
public class HeuristicPlayer
extends Player {
private ArrayList<Integer[]> path;
public HeuristicPlayer() {
super ();
path = new ArrayList<Integer[]>();
}
HeuristicPlayer (int playerId, String name, Board board) {
super (playerId, name, board);
path = new ArrayList<Integer[]>();
}
@Override
int dice () {
return 1;
}
@Override
int getNextMove (int tile) {
Map<Integer, Double> moves = new HashMap<Integer, Double>();
double max = Double.NEGATIVE_INFINITY;
double ev = Double.NEGATIVE_INFINITY;
int roll = 0;
for (int r=1 ; r<=6 ; ++r) {
moves.put (new Integer(r), evaluate (tile, r));
if ((ev = moves.get(r)) > max) {
max = ev;
roll = r;
}
}
Integer[] move_data = Arrays.stream(move (tile, roll, true))
.boxed()
.toArray(Integer[]::new);
path.add(move_data);
return tile + roll;
}
@Override
void statistics (boolean verbose, boolean sum) {
if (sum) {
int nSnakes =0;
int nLadders =0;
int nRedApples =0;
int nBlackApples =0;
for (int i=0 ; i<path.size() ; ++i) {
nSnakes += path.get(i)[MOVE_SNAKES_IDX];
nLadders+= path.get(i)[MOVE_LADDERS_IDX];
nRedApples += path.get(i)[MOVE_RED_APPLES_IDX];
nBlackApples += path.get(i)[MOVE_BLACK_APPLES_IDX];
}
System.out.println("");
System.out.println("*** Statistics for " + name + " ***");
System.out.println(" Number of Snake bites : " + nSnakes);
System.out.println(" Number of Ladders used : " + nLadders);
System.out.println(" Number of Red Apples eaten : " + nRedApples);
System.out.println(" Number of Black Apples eaten: " + nBlackApples);
}
else
super.statistics(verbose, sum);
}
private double evaluate (int tile, int roll) {
int[] check = new int[MOVE_DATA_SIZE];
check = move(tile, roll, false);
return 0.65*check[MOVE_STEPS_IDX] + 0.35*check[MOVE_POINTS_IDX];
}
}

+ 98
- 40
src/net/hoo2/auth/dsproject/snake/Player.java View File

@@ -1,5 +1,7 @@
package net.hoo2.auth.dsproject.snake; package net.hoo2.auth.dsproject.snake;
import java.util.Arrays;
/** /**
* @class Player * @class Player
* @brief Represent a Player in the Game * @brief Represent a Player in the Game
@@ -11,13 +13,26 @@ package net.hoo2.auth.dsproject.snake;
* @email cchoutou@ece.auth.gr * @email cchoutou@ece.auth.gr
*/ */
public class Player { public class Player {
static final int MOVE_DATA_SIZE = 9;
static final int MOVE_TILE_IDX = 0;
static final int MOVE_INITTILE_IDX = 1;
static final int MOVE_STEPS_IDX = 2;
static final int MOVE_ROLL_IDX = 3;
static final int MOVE_POINTS_IDX = 4;
static final int MOVE_SNAKES_IDX = 5; // Always <= 1
static final int MOVE_LADDERS_IDX = 6; // Always <= 1
static final int MOVE_RED_APPLES_IDX = 7; // Always <= 1
static final int MOVE_BLACK_APPLES_IDX = 8; // Always <= 1
/** @name Constructors */ /** @name Constructors */
/** @{ */ /** @{ */
/** Default doing nothing constructor */ /** Default doing nothing constructor */
Player () { Player () {
playerId = score = tile = turn = 0;
playerId = score = tile = 0;
name = ""; name = "";
board = null; board = null;
lastMove = new int[MOVE_DATA_SIZE];
dryMove = new int[MOVE_DATA_SIZE];
} }
/** /**
* @brief The main constructor * @brief The main constructor
@@ -33,7 +48,8 @@ public class Player {
this.board = board; this.board = board;
score = 0; score = 0;
tile = 0; tile = 0;
turn = 0;
lastMove = new int[MOVE_DATA_SIZE];
dryMove = new int[MOVE_DATA_SIZE];
} }
/** @} */ /** @} */
@@ -63,17 +79,29 @@ public class Player {
void setTile (int tile) { void setTile (int tile) {
this.tile = tile; this.tile = tile;
} }
/** Get turn */
int getTurn () { return turn; }
/** Set turn */
void setTurn (int turn) {
this.turn = turn;
int[] getLastMove () { return lastMove; }
void setLastMove (int[] lastMove) {
this.lastMove = lastMove;
} }
/** @} */ /** @} */
/** @name Exposed API members */ /** @name Exposed API members */
/** @{ */ /** @{ */
/**
* Dice functionality for the players
* @return An integer in the range [1 .. 6]
*/
int dice () {
return (int)(1 + Math.random()*5);
}
// Liskov substitution principle
int getNextMove (int tile) {
return move (tile, dice(), true)[MOVE_TILE_IDX];
}
/** /**
* @brief Move functionality * @brief Move functionality
* This function prints to stdout various logs about user interaction with elements * This function prints to stdout various logs about user interaction with elements
@@ -81,57 +109,87 @@ public class Player {
* @param tile The initial tile of the player * @param tile The initial tile of the player
* @param die The die to play * @param die The die to play
* @return * @return
* int[0] tile after move
* int[1] number of snake bites
* int[2] number of ladder used
* int[3] number of apples eaten
* int[MOVE_TILE_IDX (0)] tile after move
* int[MOVE_INITTILE_IDX (1)] tile before move
* int[MOVE_STEPS_IDX (2)] number of total steps for the move
* int[MOVE_ROLL_IDX (3)] the roll of the dice
* int[MOVE_POINTS_IDX (4)] the points of the move
* int[MOVE_SNAKES_IDX (5)] number of snake bites
* int[MOVE_LADDERS_IDX (6)] number of ladders used
* int[MOVE_RED_APPLES_IDX (7)] number of red apples eaten
* int[MOVE_BLACK_APPLES_IDX (8)] number of black apples eaten
*/ */
int [] move (int tile, int die) {
int [] ret = new int[4];
int [] move (int tile, int roll, boolean run) {
int t; int t;
tile += die; // Initial move
//System.out.println(name + " +" + die + "->tile: " + tile); //XXX: Debug only
Arrays.fill(dryMove, 0);
dryMove[MOVE_INITTILE_IDX] = tile;
dryMove[MOVE_ROLL_IDX] = roll;
tile += roll; // Initial move
boolean keepGoing; boolean keepGoing;
do { do {
keepGoing = false; keepGoing = false;
// Check apples // Check apples
t = board.checkApple(tile);
if (t != 0) {
score += t;
++ret[3];
System.out.println(name + " Apple @" + tile + " " + t + " points");
if ((t = board.checkApple(tile, run)) != 0) {
dryMove[MOVE_POINTS_IDX] += t;
if (t > 0)
++dryMove[MOVE_RED_APPLES_IDX];
else
++dryMove[MOVE_BLACK_APPLES_IDX];
} }
// Check ladder // Check ladder
t = board.checkLadder(tile);
if (t != tile) {
System.out.println(name + " Ladder @" + tile + " new position " + t);
if ((t = board.checkLadder(tile, run)) != tile) {
tile = t; tile = t;
++ret[2];
++dryMove[MOVE_LADDERS_IDX];
keepGoing = true; keepGoing = true;
} }
// Check snakes // Check snakes
t = board.checkSnake(tile);
if (t != tile) {
System.out.println(name + " Ouch!! Snake @" + tile + " new position " + t);
if ((t = board.checkSnake(tile)) != tile) {
tile = t; tile = t;
++ret[1];
++dryMove[MOVE_SNAKES_IDX];
keepGoing = true; keepGoing = true;
} }
} while (keepGoing); } while (keepGoing);
ret[0] = this.tile = tile;
return ret;
dryMove[MOVE_TILE_IDX] = tile;
dryMove[MOVE_STEPS_IDX]= tile - dryMove[MOVE_INITTILE_IDX];
if (run) {
lastMove = dryMove.clone();
this.tile = lastMove[MOVE_TILE_IDX];
score += lastMove[MOVE_POINTS_IDX];
}
return dryMove;
} }
/**@} */
/** @name Data members (private) */
//Liskov substitution principle
void statistics (boolean verbose, boolean sum) {
int begin = lastMove[MOVE_INITTILE_IDX];
int roll = lastMove[MOVE_ROLL_IDX];
int last = lastMove[MOVE_TILE_IDX];
if (verbose)
System.out.println(name + " +" + roll + "->tile: " + (begin + roll));
if (lastMove[MOVE_RED_APPLES_IDX] > 0)
System.out.println(name + " Apple " + lastMove[MOVE_POINTS_IDX] + " points");
if (lastMove[MOVE_BLACK_APPLES_IDX] > 0)
System.out.println(name + " Apple " + lastMove[MOVE_POINTS_IDX] + " points");
if (lastMove[MOVE_LADDERS_IDX] > 0)
System.out.println(name + " Ladder @" + (begin + roll) + " new position " + last);
if (lastMove[MOVE_SNAKES_IDX] > 0)
System.out.println(name + " Ouch!! Snake @" + (begin + roll) + " new position " + last);
// No use of sum here
}
/**@} */
/** @name Data members package access only */
/** @{ */ /** @{ */
private int playerId; /**< Player's ID */
private String name; /**< Player's name */
private int score; /**< Player's score */
private Board board; /**< Reference to current board */
private int tile; /**< Player's tile location */
private int turn; /**< Player's turn of playing */
int playerId; /**< Player's ID */
String name; /**< Player's name */
int score; /**< Player's score */
Board board; /**< Reference to current board */
int tile; /**< Player's tile location */
int[] lastMove;
private int [] dryMove;
/** @} */ /** @} */
} }

Loading…
Cancel
Save