A first version of the new structure
This commit is contained in:
parent
0a05f42b38
commit
4b3a936391
@ -223,11 +223,11 @@ public class Board {
|
||||
* @param tile The tile to check
|
||||
* @return The result tile
|
||||
*/
|
||||
int checkLadder (int tile) {
|
||||
int checkLadder (int tile, boolean climb) {
|
||||
for (int i =0 ; i<ladders.length ; ++i) {
|
||||
if (ladders[i].getDownStepId() == tile &&
|
||||
ladders[i].getBroken() == false) {
|
||||
ladders[i].setBroken(true);
|
||||
ladders[i].setBroken(climb);
|
||||
return ladders[i].getUpStepId();
|
||||
}
|
||||
}
|
||||
@ -239,12 +239,13 @@ public class Board {
|
||||
* @param tile The tile to check
|
||||
* @return The score difference
|
||||
*/
|
||||
int checkApple (int tile) {
|
||||
int checkApple (int tile, boolean eat) {
|
||||
int ds =0; // delta-score
|
||||
for (int i =0 ; i<apples.length ; ++i) {
|
||||
if (apples[i].getAppleTileId() == tile) {
|
||||
// eat it
|
||||
ds = apples[i].getPoints();
|
||||
// eat it
|
||||
if (eat)
|
||||
apples[i].setPoints(0);
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,7 @@ package net.hoo2.auth.dsproject.snake;
|
||||
* @author Christos Choutouridis AEM:8997
|
||||
* @email cchoutou@ece.auth.gr
|
||||
*/
|
||||
|
||||
import java.lang.Math;
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @class Game
|
||||
@ -31,8 +29,8 @@ import java.util.ArrayList;
|
||||
public class Game {
|
||||
/** @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 */
|
||||
@ -40,17 +38,12 @@ public class Game {
|
||||
private int round; /**< The current round of the game */
|
||||
private Board board; /**< A reference to board */
|
||||
private ArrayList<Player> players; /**< A reference to players */
|
||||
private Map<Integer, Integer> playingOrder;
|
||||
/** @} */
|
||||
|
||||
/** @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
|
||||
* 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
|
||||
* @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 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;
|
||||
board = new Board();
|
||||
players = new ArrayList<>();
|
||||
playingOrder
|
||||
= new HashMap<Integer, Integer>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,6 +108,8 @@ public class Game {
|
||||
// delegate constructors
|
||||
board = new Board (N, M, numOfSnakes, numOfLadders, numOfApples);
|
||||
players = new ArrayList<>();
|
||||
playingOrder
|
||||
= new HashMap<Integer, Integer>();
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@ -118,6 +136,11 @@ public class Game {
|
||||
void setPlayers(ArrayList<Player> players) {
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
Map<Integer, Integer> getPlayingOrder () { return playingOrder; }
|
||||
void setPlayingOrder (Map<Integer, Integer> playingOrder) {
|
||||
this.playingOrder = playingOrder;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** @name Public functionality */
|
||||
@ -134,26 +157,49 @@ public class Game {
|
||||
players.add(new Player(playerId, name, board));
|
||||
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
|
||||
* 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())
|
||||
);
|
||||
}
|
||||
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
|
||||
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 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
|
||||
*/
|
||||
@ -168,17 +214,19 @@ public class Game {
|
||||
*
|
||||
* @return The winner if we have one, or null
|
||||
*/
|
||||
Player round () {
|
||||
int [] mret;
|
||||
Player round (boolean verbose) {
|
||||
int tile;
|
||||
++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())
|
||||
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
|
||||
return players.get(i);
|
||||
return p;
|
||||
}
|
||||
return null; // No one finished yet
|
||||
}
|
||||
@ -203,6 +251,7 @@ public class Game {
|
||||
int numOfLadders = 3;
|
||||
int numOfApples = 6;
|
||||
int numOfPlayers = 2;
|
||||
boolean verbose = false;
|
||||
|
||||
// Print caption
|
||||
System.out.println("================== Snake Game ==================");
|
||||
@ -214,14 +263,18 @@ public class Game {
|
||||
Game game = new Game (lines, columns, numOfSnakes, numOfLadders, numOfApples);
|
||||
// game.getBoard().createElementBoard(); // Not explicitly required
|
||||
|
||||
// Player registration
|
||||
for (int i=0 ; i<numOfPlayers && i<MAX_PLAYERS; ++i)
|
||||
// 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.playOrder(); // Choose play order
|
||||
}
|
||||
game.setTurns(game.getPlayers()); // Choose play order
|
||||
|
||||
Player winner;
|
||||
do // Keep going until someone finishes
|
||||
winner = game.round ();
|
||||
winner = game.round (verbose);
|
||||
while (winner == null
|
||||
&& game.getRound() < MAX_GAME_ROUNDS);
|
||||
if (game.getRound() == MAX_GAME_ROUNDS) {
|
||||
@ -231,8 +284,10 @@ public class Game {
|
||||
}
|
||||
|
||||
// Print the results
|
||||
System.out.println("***** Game finished *****");
|
||||
System.out.println("*** Game finished ***");
|
||||
System.out.println("");
|
||||
System.out.println("");
|
||||
System.out.println("*** Game Results ***");
|
||||
System.out.println("Rounds: " + game.getRound());
|
||||
System.out.println("Winner: " + winner.getName() + " [" + winner.getScore() +" points]");
|
||||
System.out.println("Score: ");
|
||||
@ -245,5 +300,11 @@ public class Game {
|
||||
else
|
||||
System.out.println(" " +p.getName() + ": " + p.getScore() +" points");
|
||||
}
|
||||
|
||||
for (Player p : game.getPlayers()) {
|
||||
if (p.getClass().getSimpleName().equals("HeuristicPlayer"))
|
||||
p.statistics(verbose, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
80
src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java
Normal file
80
src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java
Normal 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];
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package net.hoo2.auth.dsproject.snake;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @class Player
|
||||
* @brief Represent a Player in the Game
|
||||
@ -11,13 +13,26 @@ package net.hoo2.auth.dsproject.snake;
|
||||
* @email cchoutou@ece.auth.gr
|
||||
*/
|
||||
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 */
|
||||
/** @{ */
|
||||
/** Default doing nothing constructor */
|
||||
Player () {
|
||||
playerId = score = tile = turn = 0;
|
||||
playerId = score = tile = 0;
|
||||
name = "";
|
||||
board = null;
|
||||
lastMove = new int[MOVE_DATA_SIZE];
|
||||
dryMove = new int[MOVE_DATA_SIZE];
|
||||
}
|
||||
/**
|
||||
* @brief The main constructor
|
||||
@ -33,7 +48,8 @@ public class Player {
|
||||
this.board = board;
|
||||
score = 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) {
|
||||
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 */
|
||||
/** @{ */
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 die The die to play
|
||||
* @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;
|
||||
|
||||
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;
|
||||
do {
|
||||
keepGoing = false;
|
||||
// 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
|
||||
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;
|
||||
++ret[2];
|
||||
++dryMove[MOVE_LADDERS_IDX];
|
||||
keepGoing = true;
|
||||
}
|
||||
// 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;
|
||||
++ret[1];
|
||||
++dryMove[MOVE_SNAKES_IDX];
|
||||
keepGoing = true;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
//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 (private) */
|
||||
/** @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…
x
Reference in New Issue
Block a user