Part 3 code
This commit is contained in:
parent
b583d63095
commit
3b3eda4090
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
*.classpath
|
||||
*.pdf
|
||||
|
||||
/bin/
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.hoo2.auth.dsproject.snake;
|
||||
|
||||
import java.lang.Math;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @class Board
|
||||
@ -33,6 +34,7 @@ public class Board {
|
||||
snakes = null;
|
||||
ladders = null;
|
||||
apples = null;
|
||||
players = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,6 +66,7 @@ public class Board {
|
||||
snakes = new Snake[numOfSnakes];
|
||||
ladders = new Ladder[numOfLadders];
|
||||
apples = new Apple[numOfApples];
|
||||
players = null;
|
||||
createBoard (); // Complete board preparation and make all the element memory allocations
|
||||
}
|
||||
|
||||
@ -81,6 +84,7 @@ public class Board {
|
||||
snakes = new Snake[B.getSnakes().length];
|
||||
ladders = new Ladder[B.getLadders().length];
|
||||
apples = new Apple[B.getApples().length];
|
||||
players = B.getPlayers(); // reference only (don't need to clone)
|
||||
// Copy B's guts into new memory
|
||||
copyTiles(B.getTiles());
|
||||
copySnakes(B.getSnakes());
|
||||
@ -139,6 +143,13 @@ public class Board {
|
||||
*/
|
||||
void setApples(Apple[] apples) { this.apples = apples; }
|
||||
|
||||
/** get reference to players */
|
||||
ArrayList<Player> getPlayers() { return players; }
|
||||
/** set reference to players */
|
||||
void setPlayers (ArrayList<Player> players) {
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy tiles
|
||||
* @param tiles Source of tiles to use
|
||||
@ -552,6 +563,7 @@ public class Board {
|
||||
private Snake[] snakes; /**< Board's snakes */
|
||||
private Ladder[] ladders; /**< Board's ladders */
|
||||
private Apple[] apples; /**< Board's apples */
|
||||
private ArrayList<Player> players; /**< oard's copy of players reference vector */
|
||||
/** @} */
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ package net.hoo2.auth.dsproject.snake;
|
||||
|
||||
/**
|
||||
* @mainpage
|
||||
* @title Snake game project. -- Part 2 --
|
||||
* @title Snake game project. -- Part 3 --
|
||||
*
|
||||
* This is the code documentation page of the Snake game project.
|
||||
* Listed are:
|
||||
@ -173,20 +173,35 @@ public class Game {
|
||||
boolean registerPlayer (int playerId, String name) {
|
||||
if (players.size() >= MAX_PLAYERS)
|
||||
return false;
|
||||
players.add(new Player(playerId, name, board));
|
||||
players.add(new Player(playerId, name));
|
||||
return true;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Register a heuristic 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));
|
||||
// players.add(new HeuristicPlayer(playerId, name));
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Register a heuristic 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) {
|
||||
boolean registerMinMaxPlayer (int playerId, String name) {
|
||||
if (players.size() >= MAX_PLAYERS)
|
||||
return false;
|
||||
players.add(new HeuristicPlayer(playerId, name, board));
|
||||
//players.add(new HeuristicPlayer(playerId, name, board));
|
||||
players.add(new MinMaxPlayer(playerId, name));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -246,7 +261,7 @@ public class Game {
|
||||
// using a dice throw
|
||||
for (Integer pid : playingOrder.keySet()) {
|
||||
Player p = _getPlayer(pid);
|
||||
tile = p.getNextMove (p.getTile());
|
||||
tile = p.getNextMove (board, p.getTile())[0];
|
||||
p.statistics(verbose, false);
|
||||
if (tile>= board.getN()*board.getM())
|
||||
// The first one here is the winner
|
||||
@ -275,7 +290,7 @@ public class Game {
|
||||
int numOfLadders = 3;
|
||||
int numOfApples = 6;
|
||||
int numOfPlayers = 2;
|
||||
boolean verbose = false;
|
||||
boolean verbose = true;
|
||||
|
||||
// Print caption
|
||||
System.out.println("================== Snake Game ==================");
|
||||
@ -290,14 +305,14 @@ public class Game {
|
||||
// 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));
|
||||
game.registerMinMaxPlayer(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
|
||||
|
||||
game.setTurns(game.getPlayers()); // Choose play order
|
||||
game.board.setPlayers(game.getPlayers()); // inform the board with the players
|
||||
Player winner;
|
||||
do // Keep going until someone finishes
|
||||
do // Keep going until someone finishes
|
||||
winner = game.round (verbose);
|
||||
while (winner == null
|
||||
&& game.getRound() < MAX_GAME_ROUNDS);
|
||||
|
@ -31,8 +31,8 @@ public class HeuristicPlayer
|
||||
* @param name The name of the player
|
||||
* @param board Reference to the board the player will play on.
|
||||
*/
|
||||
HeuristicPlayer (int playerId, String name, Board board) {
|
||||
super (playerId, name, board);
|
||||
HeuristicPlayer (int playerId, String name) {
|
||||
super (playerId, name);
|
||||
path = new ArrayList<Integer[]>();
|
||||
}
|
||||
/* @} */
|
||||
|
290
src/net/hoo2/auth/dsproject/snake/MinMaxPlayer.java
Normal file
290
src/net/hoo2/auth/dsproject/snake/MinMaxPlayer.java
Normal file
@ -0,0 +1,290 @@
|
||||
package net.hoo2.auth.dsproject.snake;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @class MinMaxPlayer
|
||||
* @brief Represent a MinMax Player in the Game
|
||||
*
|
||||
* The players are playing in a round-robin sequence and we keep track
|
||||
* for each one of them their playing order, score and place on the board.
|
||||
* This kind of player, is a cheater. He can control the dice. Not fair dude.
|
||||
*
|
||||
* @author Christos Choutouridis AEM:8997
|
||||
* @email cchoutou@ece.auth.gr
|
||||
*/
|
||||
public class MinMaxPlayer
|
||||
extends Player {
|
||||
static final int MINIMAX_TREE_DEPTH = 2; /**< The maximum depth of the minimax tree */
|
||||
/** @name Constructors */
|
||||
/** @{ */
|
||||
/** Default doing nothing constructor */
|
||||
public MinMaxPlayer() {
|
||||
super ();
|
||||
path = new ArrayList<Integer[]>();
|
||||
}
|
||||
/**
|
||||
* @brief The main constructor
|
||||
*
|
||||
* This creates a player for the game
|
||||
* @param playerId The player's to create
|
||||
* @param name The name of the player
|
||||
* @param board Reference to the board the player will play on.
|
||||
*/
|
||||
MinMaxPlayer (int playerId, String name) {
|
||||
super (playerId, name);
|
||||
path = new ArrayList<Integer[]>();
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/** @name Get/Set interface */
|
||||
/** @{ */
|
||||
ArrayList<Integer[]> getPath() { return path; }
|
||||
void setPath (ArrayList<Integer[]> path) {
|
||||
this.path = path;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Override dice functionality for the player
|
||||
* @return As this is called from the game only to select playing order
|
||||
* we cheat and return 1
|
||||
*/
|
||||
@Override
|
||||
int dice () {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override get the next move after the user's move
|
||||
* @param board The board in which we play on
|
||||
* @param tile The initial tile
|
||||
* @return The the move as an array
|
||||
* See @ref Node.nodeMove
|
||||
*/
|
||||
@Override
|
||||
int[] getNextMove (Board board, int tile) {
|
||||
int [] ret = new int[4];
|
||||
Node root = new Node (board);
|
||||
|
||||
createMySubtree(root, 1, tile, selectOpponent(board).getTile());
|
||||
// Evaluate each possible dice result and find the better one
|
||||
Node r = MaxValue (root, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
// Do the move and get the move data
|
||||
Integer[] move_data = Arrays.stream (move (board, tile, r.getNodeMove()[3], true))
|
||||
.boxed()
|
||||
.toArray(Integer[]::new);
|
||||
// Store the move data
|
||||
path.add(move_data);
|
||||
ret[0] = move_data[MOVE_TILE_IDX];
|
||||
ret[1] = move_data[MOVE_INITTILE_IDX];
|
||||
ret[2] = move_data[MOVE_POINTS_IDX];
|
||||
ret[3] = move_data[MOVE_ROLL_IDX];
|
||||
return ret; // return the new tile position
|
||||
}
|
||||
|
||||
/**
|
||||
* The MinMax statistics version
|
||||
* @param verbose Flag to select the verbosity
|
||||
* @param sum Flag to select if we need to print a summarize of the user history
|
||||
*/
|
||||
@Override
|
||||
void statistics (boolean verbose, boolean sum) {
|
||||
if (sum) {
|
||||
// If we run the summarize
|
||||
int nSnakes =0;
|
||||
int nLadders =0;
|
||||
int nRedApples =0;
|
||||
int nBlackApples =0;
|
||||
|
||||
// Calculate frequencies
|
||||
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];
|
||||
}
|
||||
// Print the results
|
||||
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
|
||||
// Call the base version
|
||||
super.statistics(verbose, sum);
|
||||
}
|
||||
|
||||
/** @name Private helper API */
|
||||
/** @{ */
|
||||
/**
|
||||
* Select the the best Opponent
|
||||
* @param board Reference to current board
|
||||
* @return Reference to the player who is most far in the board
|
||||
*/
|
||||
private Player selectOpponent (Board board) {
|
||||
Player opp = null;
|
||||
int max_tile = Integer.MIN_VALUE;
|
||||
for (Player p : board.getPlayers()) {
|
||||
if (p == this) // Please do not return me
|
||||
continue;
|
||||
if (opp == null) opp = p; // init variable
|
||||
if (p.getTile() > max_tile) { // max filtering
|
||||
opp = p;
|
||||
max_tile = p.getTile();
|
||||
}
|
||||
}
|
||||
return opp;
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the 2 recursive functions for creating the minimax tree. This one
|
||||
* creates children for the MinMax player
|
||||
* @param parent The parent Node
|
||||
* @param depth the current depth for the children
|
||||
* @param tile the tile of MinMax player
|
||||
* @param oppTile the tile of the best opponent
|
||||
*/
|
||||
private void createMySubtree (Node parent, int depth, int tile, int oppTile) {
|
||||
int [] moveData;
|
||||
int [] nodeMove;
|
||||
for (int roll = 1 ; roll <= 6 ; ++roll) {
|
||||
Board nodeBoard = new Board (parent.getNodeBoard()); // clone board
|
||||
moveData = move (nodeBoard, tile, roll, false); // simulate move
|
||||
nodeMove = new int[4]; // create nodeMove
|
||||
nodeMove[0] = moveData[MOVE_TILE_IDX];
|
||||
nodeMove[1] = moveData[MOVE_INITTILE_IDX];
|
||||
nodeMove[2] = moveData[MOVE_POINTS_IDX];
|
||||
nodeMove[3] = moveData[MOVE_ROLL_IDX];
|
||||
// make child Node
|
||||
Node child = new Node (parent, depth, nodeMove, nodeBoard);
|
||||
parent.addChild(child); // add child to tree
|
||||
createOppSubtree (child, depth+1, nodeMove[0], oppTile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the 2 recursive functions for creating the minimax tree. This one
|
||||
* creates children for the opponent player
|
||||
* @param parent The parent Node
|
||||
* @param depth the current depth for the children
|
||||
* @param tile the tile of MinMax player
|
||||
* @param oppTile the tile of the best opponent
|
||||
*/
|
||||
private void createOppSubtree (Node parent, int depth, int tile, int oppTile) {
|
||||
int [] moveData;
|
||||
int [] nodeMove;
|
||||
for (int roll =1 ; roll <= 6 ; ++roll) {
|
||||
Board nodeBoard = new Board(parent.getNodeBoard()); // clone board
|
||||
moveData = move (nodeBoard, oppTile, roll, false); // simulate move
|
||||
nodeMove = new int[4];
|
||||
nodeMove[0] = moveData[MOVE_TILE_IDX];
|
||||
nodeMove[1] = moveData[MOVE_INITTILE_IDX];
|
||||
nodeMove[2] = moveData[MOVE_POINTS_IDX];
|
||||
nodeMove[3] = moveData[MOVE_ROLL_IDX];
|
||||
Node child = new Node (parent, depth, nodeMove, nodeBoard); // make child Node
|
||||
parent.addChild(child); // add child to tree
|
||||
if (depth >= MINIMAX_TREE_DEPTH) {
|
||||
child.setNodeEvaluation(
|
||||
evaluate(parent.getNodeMove()[0], // our tile
|
||||
parent.getNodeMove()[0] - parent.getNodeMove()[1], // our steps
|
||||
parent.getNodeMove()[2], // our points
|
||||
nodeMove[0]) // opponent tile
|
||||
);
|
||||
}
|
||||
else {
|
||||
createMySubtree (child, depth+1, tile, nodeMove[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The main evaluation function
|
||||
* @param tile The current tile of the player
|
||||
* @param steps The total steps of the move
|
||||
* @param points The total points of the move
|
||||
* @param oppTile The tile of the best opponent
|
||||
* @return The evaluation of the roll
|
||||
*/
|
||||
private double evaluate (int tile, int steps, int points, int oppTile) {
|
||||
if (tile > oppTile)
|
||||
return 0.65*steps + 0.35*points;
|
||||
else
|
||||
return 0.8*steps + 0.2*points - (oppTile - tile)*0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Minimax recursive function for the maximizing part
|
||||
* @param s The current Node
|
||||
* @param a The alpha for pruning
|
||||
* @param b The beta for pruning
|
||||
* @return The selected Node
|
||||
*/
|
||||
private Node MaxValue (Node s, double a, double b) {
|
||||
if (s.getChildren() == null)
|
||||
return s;
|
||||
else {
|
||||
Node r = null;
|
||||
double vv, v = Double.NEGATIVE_INFINITY;
|
||||
for (Node c : s.getChildren()) {
|
||||
if (r == null) r = c;
|
||||
vv = MinValue (c, a, b).getNodeEvaluation();
|
||||
//v = max (v, vv);
|
||||
if (vv > v) {
|
||||
v = vv;
|
||||
r = c;
|
||||
}
|
||||
if (vv >= b)
|
||||
return c; // prune
|
||||
a = max (a, vv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Minimax recursive function for the minimizing part
|
||||
* @param s The current Node
|
||||
* @param a The alpha for pruning
|
||||
* @param b The beta for pruning
|
||||
* @return The selected Node
|
||||
*/
|
||||
private Node MinValue (Node s, double a, double b) {
|
||||
if (s.getChildren() == null)
|
||||
return s;
|
||||
else {
|
||||
Node r = null;
|
||||
double vv, v = Double.POSITIVE_INFINITY;
|
||||
for (Node c : s.getChildren()) {
|
||||
if (r == null) r = c;
|
||||
vv = MaxValue (c, a, b).getNodeEvaluation();
|
||||
//v = min (v, vv);
|
||||
if (vv < v) {
|
||||
v = vv;
|
||||
r = c;
|
||||
}
|
||||
if (vv <= a)
|
||||
return c; // prune
|
||||
b = min (b, vv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the minimum of x and y */
|
||||
private static double min (double x, double y) {
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
/** return the maximum of x and y */
|
||||
private static double max (double x, double y) {
|
||||
return (x > y) ? x : y;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** @name Data members package access only */
|
||||
/** @{ */
|
||||
private ArrayList<Integer[]> path; /**< Players history as required */
|
||||
/** @} */
|
||||
}
|
102
src/net/hoo2/auth/dsproject/snake/Node.java
Normal file
102
src/net/hoo2/auth/dsproject/snake/Node.java
Normal file
@ -0,0 +1,102 @@
|
||||
package net.hoo2.auth.dsproject.snake;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @class Node
|
||||
* @brief Represent a node in the Minimax tre
|
||||
*
|
||||
* @author Christos Choutouridis AEM:8997
|
||||
* @email cchoutou@ece.auth.gr
|
||||
*/
|
||||
class Node {
|
||||
|
||||
|
||||
/** @name Constructors */
|
||||
/** @{ */
|
||||
/** Null initialize constructor */
|
||||
Node () { }
|
||||
/** The main constructor for the Node */
|
||||
Node (Node parent, int nodeDepth, int [] nodeMove, Board nodeBoard) {
|
||||
this.parent = parent;
|
||||
this.children = null;
|
||||
this.nodeDepth = nodeDepth;
|
||||
this.nodeMove = nodeMove;
|
||||
this.nodeBoard = nodeBoard;
|
||||
this.nodeEvaluation = 0;
|
||||
}
|
||||
/** A special constructor for creating a root Node */
|
||||
Node (Board nodeBoard) {
|
||||
this.parent = null;
|
||||
this.children = null;
|
||||
this.nodeDepth = 0;
|
||||
this.nodeMove = new int [4];
|
||||
this.nodeBoard = nodeBoard;
|
||||
this.nodeEvaluation = 0;
|
||||
}
|
||||
/**@} */
|
||||
|
||||
/** @name Get/Set interface */
|
||||
/** @{ */
|
||||
/** Get parent */
|
||||
Node getParent() { return parent; }
|
||||
/** get children */
|
||||
ArrayList<Node>
|
||||
getChildren() { return children; }
|
||||
/** get nodeDepth */
|
||||
int getNodeDepth() { return nodeDepth; }
|
||||
/** get nodeMove */
|
||||
int[] getNodeMove() { return nodeMove; }
|
||||
/** get nodeBoard */
|
||||
Board getNodeBoard() { return nodeBoard; }
|
||||
/** get nodeEvluation */
|
||||
double getNodeEvaluation (){ return nodeEvaluation; }
|
||||
|
||||
/** set parent */
|
||||
void setParent(Node parent) { this.parent = parent; }
|
||||
/** set children */
|
||||
void setChildren(ArrayList<Node> children) {
|
||||
this.children = children;
|
||||
}
|
||||
/** set nodeDepth */
|
||||
void setNodeDepth(int nodeDepth) {
|
||||
this.nodeDepth = nodeDepth;
|
||||
}
|
||||
/** set nodeMove */
|
||||
void setNodeMove(int[] nodeMove) {
|
||||
this.nodeMove = nodeMove;
|
||||
}
|
||||
/** set nodeBoard */
|
||||
void setNodeBoard(Board nodeBoard) {
|
||||
this.nodeBoard = nodeBoard;
|
||||
}
|
||||
/** set nodeEvaluation */
|
||||
void setNodeEvaluation(double nodeEvaluation) {
|
||||
this.nodeEvaluation = nodeEvaluation;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
/** @name Public API */
|
||||
/** @{ */
|
||||
/**
|
||||
* Add a child to the tree
|
||||
* @param child The child to add
|
||||
* @return the status of the operation
|
||||
*/
|
||||
boolean addChild (Node child) {
|
||||
if (children == null)
|
||||
children = new ArrayList<>();
|
||||
return children.add(child);
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
/** @name Data members */
|
||||
/** @{ */
|
||||
private Node parent; /**< Back reference to parent Node */
|
||||
private ArrayList<Node> children; /**< Fwd reference to leaf Nodes */
|
||||
private int nodeDepth; /**< The Node's depth */
|
||||
private int[] nodeMove; /**< The Node's move data [tile, initTile, points, roll]*/
|
||||
private Board nodeBoard; /**< Reference to Board's copy of the current node*/
|
||||
private double nodeEvaluation; /**< The Node's evaluation result */
|
||||
/**@}*/
|
||||
}
|
@ -32,7 +32,6 @@ public class Player {
|
||||
Player () {
|
||||
playerId = score = tile = 0;
|
||||
name = "";
|
||||
board = null;
|
||||
lastMove = new int[MOVE_DATA_SIZE];
|
||||
dryMove = new int[MOVE_DATA_SIZE];
|
||||
}
|
||||
@ -44,10 +43,9 @@ public class Player {
|
||||
* @param name The name of the player
|
||||
* @param board Reference to the board the player will play on.
|
||||
*/
|
||||
Player (int playerId, String name, Board board) {
|
||||
Player (int playerId, String name) {
|
||||
this.playerId = playerId;
|
||||
this.name = name;
|
||||
this.board = board;
|
||||
score = 0;
|
||||
tile = 0;
|
||||
lastMove = new int[MOVE_DATA_SIZE];
|
||||
@ -69,12 +67,7 @@ public class Player {
|
||||
void setScore (int score) {
|
||||
this.score = score;
|
||||
}
|
||||
/** Get reference to Board */
|
||||
Board getBoard () { return board; }
|
||||
/** Set Board reference */
|
||||
void setBoard (Board board) {
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
/** Get tile */
|
||||
int getTile () { return tile; }
|
||||
/** Set tile */
|
||||
@ -109,16 +102,25 @@ public class Player {
|
||||
|
||||
/**
|
||||
* Get the next tile after the user's move
|
||||
* @param board The board in which we play on
|
||||
* @param tile The initial tile
|
||||
* @return The tile after the move
|
||||
* @return The the move as an array
|
||||
* [0]: Tile after move
|
||||
* [1]: The roll of the dice
|
||||
* @note
|
||||
* We add this move() wrapper in order to provide polymorphism to
|
||||
* Player class hierarchy and to be sure that we are not braking the
|
||||
* Liskov substitution principle
|
||||
* @see https://en.wikipedia.org/wiki/Liskov_substitution_principle
|
||||
*/
|
||||
int getNextMove (int tile) {
|
||||
return move (tile, dice(), true)[MOVE_TILE_IDX];
|
||||
int[] getNextMove (Board board, int tile) {
|
||||
int [] ret = new int[4]; // allocate move memory
|
||||
move (board, tile, dice(), true); // make the move
|
||||
ret[0] = dryMove[MOVE_TILE_IDX];
|
||||
ret[1] = dryMove[MOVE_INITTILE_IDX];
|
||||
ret[2] = dryMove[MOVE_POINTS_IDX];
|
||||
ret[3] = dryMove[MOVE_ROLL_IDX];
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +151,7 @@ public class Player {
|
||||
* We could also had members like: <pre> MoveData previous; </pre> to help us further.
|
||||
* We kept this representation just because it was a requirement.
|
||||
*/
|
||||
int [] move (int tile, int roll, boolean run) {
|
||||
int [] move (Board board, int tile, int roll, boolean run) {
|
||||
int t;
|
||||
|
||||
Arrays.fill(dryMove, 0);
|
||||
@ -161,7 +163,8 @@ public class Player {
|
||||
do {
|
||||
keepGoing = false;
|
||||
// Check apples
|
||||
if ((t = board.checkApple(tile, run)) != 0) {
|
||||
//if ((t = board.checkApple(tile, run)) != 0) {
|
||||
if ((t = board.checkApple(tile, true)) != 0) {
|
||||
dryMove[MOVE_POINTS_IDX] += t;
|
||||
if (t > 0)
|
||||
++dryMove[MOVE_RED_APPLES_IDX];
|
||||
@ -169,7 +172,8 @@ public class Player {
|
||||
++dryMove[MOVE_BLACK_APPLES_IDX];
|
||||
}
|
||||
// Check ladder
|
||||
if ((t = board.checkLadder(tile, run)) != tile) {
|
||||
//if ((t = board.checkLadder(tile, run)) != tile) {
|
||||
if ((t = board.checkLadder(tile, true)) != tile) {
|
||||
tile = t;
|
||||
++dryMove[MOVE_LADDERS_IDX];
|
||||
keepGoing = true;
|
||||
@ -226,7 +230,6 @@ public class Player {
|
||||
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; /**< move() return data for statistics. These are only valid after a true move */
|
||||
private int [] dryMove; /**< Fake (dry run) move return buffer */
|
||||
|
Loading…
x
Reference in New Issue
Block a user