DEV: 3rd assignment draft
This commit is contained in:
parent
2230cac96e
commit
c2c5d5e46f
BIN
ds_project_2020-2021_PartC.pdf
Normal file
BIN
ds_project_2020-2021_PartC.pdf
Normal file
Binary file not shown.
BIN
release/8959_8997_PartB.zip
Normal file
BIN
release/8959_8997_PartB.zip
Normal file
Binary file not shown.
@ -13,7 +13,6 @@
|
|||||||
package host.labyrinth;
|
package host.labyrinth;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,9 +34,10 @@ class Board {
|
|||||||
this.S = 0;
|
this.S = 0;
|
||||||
this.W = 0;
|
this.W = 0;
|
||||||
tiles = null;
|
tiles = null;
|
||||||
supplies =null;
|
supplies = null;
|
||||||
walls = new ArrayList<Edge>();
|
walls = new ArrayList<Edge>();
|
||||||
moves = new ArrayList<Integer[]>();
|
moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE];
|
||||||
|
playerCount =0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,7 +54,8 @@ class Board {
|
|||||||
tiles = new Tile[N*N];
|
tiles = new Tile[N*N];
|
||||||
supplies = new Supply[S];
|
supplies = new Supply[S];
|
||||||
walls = new ArrayList<Edge>();
|
walls = new ArrayList<Edge>();
|
||||||
moves = new ArrayList<Integer[]>();
|
moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE];
|
||||||
|
playerCount =0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,17 +73,28 @@ class Board {
|
|||||||
*/
|
*/
|
||||||
Board(Board b) {
|
Board(Board b) {
|
||||||
// Copy primitives
|
// Copy primitives
|
||||||
this.N = b.N;
|
this.N = b.N;
|
||||||
this.S = b.S;
|
this.S = b.S;
|
||||||
this.W = b.W;
|
this.W = b.W;
|
||||||
// Clone arrays
|
tiles = new Tile[b.tiles.length];
|
||||||
this.tiles = b.tiles.clone();
|
supplies = new Supply[b.supplies.length];
|
||||||
this.supplies = b.supplies.clone();
|
walls = new ArrayList<Edge>();
|
||||||
|
moves = new int[Const.numOfPlayers][Player.MOVE_DATA_SIZE];
|
||||||
|
playerCount =b.playerCount;
|
||||||
|
|
||||||
|
// clone moves array of array of primitives
|
||||||
|
for (int i=0 ; i<b.moves.length ; ++i)
|
||||||
|
this.moves[i] = b.moves[i].clone();
|
||||||
|
|
||||||
|
// Clone arrays of objects
|
||||||
|
for (int i=0 ; i<b.tiles.length ; ++i)
|
||||||
|
this.tiles[i] = new Tile(b.tiles[i]);
|
||||||
|
for (int i=0 ; i<b.supplies.length ; ++i)
|
||||||
|
this.supplies[i] = new Supply(b.supplies[i]);
|
||||||
|
|
||||||
|
// clone vectors
|
||||||
for (Edge it: b.walls)
|
for (Edge it: b.walls)
|
||||||
this.walls.add(new Edge(it));
|
this.walls.add(new Edge(it));
|
||||||
for (Integer[] m : b.moves) {
|
|
||||||
this.moves.add(m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
@ -219,30 +231,35 @@ class Board {
|
|||||||
/** @return the size of each site of the board. */
|
/** @return the size of each site of the board. */
|
||||||
int size () { return N; }
|
int size () { return N; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Boards utility to give access to other player moves.
|
|
||||||
*
|
|
||||||
* @param playerId The id of player who asks
|
|
||||||
* @return The moves data of all other players
|
|
||||||
*/
|
|
||||||
int[][] getOpponentMoves (int playerId) {
|
|
||||||
int[][] ret = new int[moves.size()-1][Const.moveItems];
|
|
||||||
int ii= 0, ri =0;
|
|
||||||
for (Integer[] m : moves) {
|
|
||||||
if (ii != playerId)
|
|
||||||
ret[ri++] = Arrays.stream(m).mapToInt(i->i).toArray();
|
|
||||||
++ii;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function to create player IDs
|
* Utility function to create player IDs
|
||||||
* @return The generated player id.
|
* @return The generated player id.
|
||||||
*/
|
*/
|
||||||
int generatePlayerId () {
|
int generatePlayerId () throws Exception {
|
||||||
moves.add(null);
|
if (playerCount < Const.numOfPlayers)
|
||||||
return moves.size() -1;
|
return playerCount++;
|
||||||
|
else
|
||||||
|
throw new Exception("Maximum number of players exceeded");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boards utility to give access to other player Id.
|
||||||
|
*
|
||||||
|
* @param playerId The id of player who asks
|
||||||
|
* @return The other player's Id.
|
||||||
|
*/
|
||||||
|
int getOpponentId(int playerId) {
|
||||||
|
return Const.numOfPlayers - (playerId +1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boards utility to give access to other player moves.
|
||||||
|
*
|
||||||
|
* @param playerId The id of player who asks
|
||||||
|
* @return The moves data of other player
|
||||||
|
*/
|
||||||
|
int[] getOpponentMove (int playerId) {
|
||||||
|
return moves[getOpponentId(playerId)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,7 +273,8 @@ class Board {
|
|||||||
* @param playerId The id of the player who update his/her data.
|
* @param playerId The id of the player who update his/her data.
|
||||||
*/
|
*/
|
||||||
void updateMove(int[] m, int playerId) {
|
void updateMove(int[] m, int playerId) {
|
||||||
moves.set(playerId, Arrays.stream(m).boxed().toArray(Integer[]::new));
|
//moves.set(playerId, Arrays.stream(m).boxed().toArray(Integer[]::new));
|
||||||
|
moves[playerId] = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
@ -295,7 +313,7 @@ class Board {
|
|||||||
* <a href="https://github.com/sean-parent/sean-parent.github.io/blob/master/better-code/03-data-structures.md"> see also here</a>
|
* <a href="https://github.com/sean-parent/sean-parent.github.io/blob/master/better-code/03-data-structures.md"> see also here</a>
|
||||||
* @return Reference to inner walls array.
|
* @return Reference to inner walls array.
|
||||||
*/
|
*/
|
||||||
ArrayList<Integer[]> getMoves() { return moves; }
|
int[][] getMoves() { return moves; }
|
||||||
|
|
||||||
void setN(int N) { this.N = N; }
|
void setN(int N) { this.N = N; }
|
||||||
void setS(int S) { this.S = S; }
|
void setS(int S) { this.S = S; }
|
||||||
@ -326,7 +344,7 @@ class Board {
|
|||||||
* @note Use with care.
|
* @note Use with care.
|
||||||
* Any call to this function will probably add memory for the garbage collector.
|
* Any call to this function will probably add memory for the garbage collector.
|
||||||
*/
|
*/
|
||||||
void setMoves(ArrayList<Integer[]> moves) { this.moves =moves; }
|
void setMoves(int[][] moves) { this.moves =moves; }
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
@ -633,6 +651,7 @@ class Board {
|
|||||||
* Array to hold all the walls using the edge representation
|
* Array to hold all the walls using the edge representation
|
||||||
* required by the closed room preventing algorithm.
|
* required by the closed room preventing algorithm.
|
||||||
*/
|
*/
|
||||||
private ArrayList<Integer[]> moves;
|
private int[][] moves;
|
||||||
|
private int playerCount;
|
||||||
/** @} */
|
/** @} */
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,23 @@ import java.util.Collections;
|
|||||||
* Class to hold constant values for entire application
|
* Class to hold constant values for entire application
|
||||||
*/
|
*/
|
||||||
class Const {
|
class Const {
|
||||||
|
static final int numOfPlayers = 2;
|
||||||
static final int maxTileWalls = 2; /**< Number of maximum walls for each tile on the board */
|
static final int maxTileWalls = 2; /**< Number of maximum walls for each tile on the board */
|
||||||
static final int noSupply =-1; /**< Number to indicate the absent of supply */
|
static final int noSupply =-1; /**< Number to indicate the absent of supply */
|
||||||
static final int noOpponent =-1; /**< Number to indicate the absent of supply */
|
static final int noOpponent =-1; /**< Number to indicate the absent of supply */
|
||||||
static final int noTileId =-1; /**< Number to indicate wrong tileId */
|
static final int noTileId =-1; /**< Number to indicate wrong tileId */
|
||||||
static final int EOR =-1; /**< Number to indicate the End Of Range */
|
static final int EOR =-1; /**< Number to indicate the End Of Range */
|
||||||
static final int moveItems =4; /**< The number of items return by move() */
|
|
||||||
static final int viewDistance =3; /**< The max distance of the Heuristic player's ability to see */
|
static final int viewDistance =3; /**< The max distance of the Heuristic player's ability to see */
|
||||||
|
static final int noView = viewDistance+1;
|
||||||
|
|
||||||
static final double opponentFactor =1.0;
|
/** Parameters to control move evaluation */
|
||||||
static final double supplyFactor =0.65;
|
/** @{ */
|
||||||
|
static final double opponentFactor = 1.0; /**< opponent distance factor */
|
||||||
|
static final double supplyFactor = 0.65; /**< supply distance factor */
|
||||||
|
static final double preMoveFactor = 0.65; /**< pre move distances factor */
|
||||||
|
static final double postMoveFactor = 0.35; /**< post move distances factor */
|
||||||
|
static final int minimaxTreeDepth = 4; /**< The maximum depth of the minimax tree */
|
||||||
|
/** @} */
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Application wide object to hold settings like values for the session.
|
* Application wide object to hold settings like values for the session.
|
||||||
@ -68,13 +75,16 @@ class Direction {
|
|||||||
static final int RIGHT =3; /**< East direction */
|
static final int RIGHT =3; /**< East direction */
|
||||||
static final int DOWN =5; /**< South direction */
|
static final int DOWN =5; /**< South direction */
|
||||||
static final int LEFT =7; /**< West direction */
|
static final int LEFT =7; /**< West direction */
|
||||||
|
static final int NONE =8; /**< No direction */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to get the opposite direction.
|
* Utility to get the opposite direction.
|
||||||
* @param direction Input direction
|
* @param direction Input direction
|
||||||
* @return The opposite direction
|
* @return The opposite direction
|
||||||
*/
|
*/
|
||||||
static int opposite (int direction) { return (direction+4)%DirRange.End; }
|
static int opposite (int direction) {
|
||||||
|
return (direction != NONE) ? (direction+4)%DirRange.End : NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static int get (int fromId, int toId) {
|
static int get (int fromId, int toId) {
|
||||||
if (Position.toID(Position.toRow(fromId), Position.toCol(fromId)-1) == toId)
|
if (Position.toID(Position.toRow(fromId), Position.toCol(fromId)-1) == toId)
|
||||||
@ -133,6 +143,7 @@ class Position {
|
|||||||
case Direction.DOWN: this.id = toID(row-1, col); break;
|
case Direction.DOWN: this.id = toID(row-1, col); break;
|
||||||
case Direction.LEFT: this.id = toID(row, col-1); break;
|
case Direction.LEFT: this.id = toID(row, col-1); break;
|
||||||
case Direction.RIGHT:this.id = toID(row, col+1); break;
|
case Direction.RIGHT:this.id = toID(row, col+1); break;
|
||||||
|
case Direction.NONE: this.id = toID(row, col); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,13 +18,14 @@
|
|||||||
* all the supplies of the board before Minotaur catches him and before the
|
* all the supplies of the board before Minotaur catches him and before the
|
||||||
* game ends.
|
* game ends.
|
||||||
*
|
*
|
||||||
* In this 2nd assignment we deal with the creation of a new heuristic player
|
* In this 3rd assignment we deal with the creation of a new minimax player
|
||||||
* who can cheat and manipulate the dice. Documented classes:
|
* who can cheat and manipulate the dice. Documented classes:
|
||||||
* - Tile
|
* - Tile
|
||||||
* - Supply
|
* - Supply
|
||||||
* - Board
|
* - Board
|
||||||
* - Player
|
* - Player
|
||||||
* - HeuristicPlayer
|
* - HeuristicPlayer
|
||||||
|
* - MinMaxPlayer
|
||||||
* - Game
|
* - Game
|
||||||
*
|
*
|
||||||
* Which are the requested classes. We also provide some extra functionalities in:
|
* Which are the requested classes. We also provide some extra functionalities in:
|
||||||
@ -156,9 +157,9 @@ public class Game {
|
|||||||
// Create a game, a board and 2 players.
|
// Create a game, a board and 2 players.
|
||||||
Game game = new Game();
|
Game game = new Game();
|
||||||
Board board = new Board(Session.boardSize, Session.supplySize);
|
Board board = new Board(Session.boardSize, Session.supplySize);
|
||||||
Player T = new HeuristicPlayer("Theseus", true, board, 0);
|
Player T = new MinMaxPlayer("Theseus", true, board, 0);
|
||||||
Player M = new Player("Minotaur", false, board, Position.toID(Session.boardSize/2, Session.boardSize/2));
|
Player M = new Player("Minotaur", false, board, Position.toID(Session.boardSize/2, Session.boardSize/2));
|
||||||
Player players [] = {T, M};
|
Player players [] = {M, T};
|
||||||
|
|
||||||
// Populate data to the board
|
// Populate data to the board
|
||||||
board.createBoard(T.playerTileId(), M.playerTileId());
|
board.createBoard(T.playerTileId(), M.playerTileId());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file Player.java
|
* @file HeuristicPlayer.java
|
||||||
*
|
*
|
||||||
* @author
|
* @author
|
||||||
* Anastasia Foti AEM:8959
|
* Anastasia Foti AEM:8959
|
||||||
@ -29,7 +29,7 @@ class HeuristicPlayer extends Player {
|
|||||||
* @param row The row coordinate of initial player position
|
* @param row The row coordinate of initial player position
|
||||||
* @param column The column coordinate of initial player's position
|
* @param column The column coordinate of initial player's position
|
||||||
*/
|
*/
|
||||||
public HeuristicPlayer(String name, boolean champion, Board board, int row, int column) {
|
public HeuristicPlayer(String name, boolean champion, Board board, int row, int column) throws Exception {
|
||||||
super(name, champion, board, row, column);
|
super(name, champion, board, row, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class HeuristicPlayer extends Player {
|
|||||||
* @param board Reference to the board of the game
|
* @param board Reference to the board of the game
|
||||||
* @param tileId The tileId coordinate of player's initial position
|
* @param tileId The tileId coordinate of player's initial position
|
||||||
*/
|
*/
|
||||||
public HeuristicPlayer(String name, boolean champion, Board board, int tileId) {
|
public HeuristicPlayer(String name, boolean champion, Board board, int tileId) throws Exception {
|
||||||
super(name, champion, board, tileId);
|
super(name, champion, board, tileId);
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
@ -58,7 +58,7 @@ class HeuristicPlayer extends Player {
|
|||||||
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
||||||
|
|
||||||
for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
|
for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
|
||||||
pos = new Position(Position.toRow(pos.getId()), Position.toCol(pos.getId()), direction);
|
pos = new Position(pos.getRow(), pos.getCol(), direction);
|
||||||
if (board.hasSupply(pos.getId()))
|
if (board.hasSupply(pos.getId()))
|
||||||
return i+1;
|
return i+1;
|
||||||
}
|
}
|
||||||
@ -73,14 +73,12 @@ class HeuristicPlayer extends Player {
|
|||||||
*/
|
*/
|
||||||
int opponetInDirection(int currentPos, int direction) {
|
int opponetInDirection(int currentPos, int direction) {
|
||||||
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
||||||
int [][] opps = board.getOpponentMoves(playerId);
|
int [] opp = board.getOpponentMove(playerId);
|
||||||
|
|
||||||
for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
|
for (int i=0 ; board.isWalkable(pos.getId(), direction) && i<Const.viewDistance ; ++i) {
|
||||||
pos = new Position(Position.toRow(pos.getId()), Position.toCol(pos.getId()), direction);
|
pos = new Position(pos.getRow(), pos.getCol(), direction);
|
||||||
for (int o =0 ; o<opps.length; ++o) {
|
if (opp[MOVE_TILE_ID] == pos.getId())
|
||||||
if (opps[o][0] == pos.getId())
|
return i+1;
|
||||||
return i+1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Const.noOpponent;
|
return Const.noOpponent;
|
||||||
}
|
}
|
||||||
@ -102,8 +100,15 @@ class HeuristicPlayer extends Player {
|
|||||||
- ((opDist != 0) ? (1.0/opDist * Const.opponentFactor) : 0);
|
- ((opDist != 0) ? (1.0/opDist * Const.opponentFactor) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must return a new move always
|
/**
|
||||||
int getNextMove(int currentPos) {
|
* Selects the best possible move to return
|
||||||
|
* @param currentPos Player's current position to the board
|
||||||
|
* @return The move array
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* This function always return a new move.
|
||||||
|
*/
|
||||||
|
int[] getNextMove(int currentPos) {
|
||||||
Range dirs = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
|
Range dirs = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
|
||||||
int N = dirs.size();
|
int N = dirs.size();
|
||||||
double[] eval = new double[N];
|
double[] eval = new double[N];
|
||||||
@ -127,7 +132,8 @@ class HeuristicPlayer extends Player {
|
|||||||
dir = directionOfMax (eval, eval_dir, N);
|
dir = directionOfMax (eval, eval_dir, N);
|
||||||
}
|
}
|
||||||
Position new_pos = new Position( Position.toRow(currentPos), Position.toCol(currentPos), dir );
|
Position new_pos = new Position( Position.toRow(currentPos), Position.toCol(currentPos), dir );
|
||||||
return new_pos.getId();
|
int [] ret = {new_pos.getId(), new_pos.getRow(), new_pos.getCol(), dir};
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,37 +150,36 @@ class HeuristicPlayer extends Player {
|
|||||||
* <li> int[0]: The tileId of the final player's position.
|
* <li> int[0]: The tileId of the final player's position.
|
||||||
* <li> int[1]: The row of the final player's position.
|
* <li> int[1]: The row of the final player's position.
|
||||||
* <li> int[2]: The column of the final player's position.
|
* <li> int[2]: The column of the final player's position.
|
||||||
* <li> int[3]: The supplyId in case player picked one (Const.noSupply otherwise).
|
* <li> int[3]: The dice/direction of the move.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
int[] move(int id) {
|
int[] move(int id) {
|
||||||
// Initialize return array with the current data
|
// Initialize return array with the current data
|
||||||
int[] ret = new int[Const.moveItems];
|
int[] ret = getNextMove(id);
|
||||||
ret[0] = getNextMove(id);
|
y = Position.toRow(ret[MOVE_TILE_ID]);
|
||||||
ret[1] = y = Position.toRow(ret[0]);
|
x = Position.toCol(ret[MOVE_TILE_ID]);
|
||||||
ret[2] = x = Position.toCol(ret[0]);
|
|
||||||
int supplyFlag =0, moveFlag =1;
|
int supplyFlag =0, moveFlag =1;
|
||||||
// In case of a champion player, try also to pick a supply
|
// In case of a champion player, try also to pick a supply
|
||||||
if (champion && (ret[3] = board.tryPickSupply(ret[0])) != Const.noSupply) {
|
if (champion && (board.tryPickSupply(ret[MOVE_TILE_ID]) != Const.noSupply)) {
|
||||||
++score; // keep score
|
++score; // keep score
|
||||||
++supplyFlag;
|
++supplyFlag;
|
||||||
}
|
}
|
||||||
int dir = Direction.get(id, ret[0]); // update direction counters
|
++dirCounter[ret[MOVE_DICE]]; // update direction counters
|
||||||
++dirCounter[dir];
|
|
||||||
board.updateMove(ret, playerId);
|
board.updateMove(ret, playerId);
|
||||||
|
|
||||||
// Update supply and opponent distance
|
// Update supply and opponent distance
|
||||||
int smin =DirRange.End, omin =DirRange.End;
|
int smin =DirRange.End, omin =DirRange.End;
|
||||||
for (int d = DirRange.Begin ; d<DirRange.End ; d += DirRange.Step) {
|
for (int d = DirRange.Begin ; d<DirRange.End ; d += DirRange.Step) {
|
||||||
int s = supplyInDirection (ret[0], d);
|
int s = supplyInDirection (ret[MOVE_TILE_ID], d);
|
||||||
int o = opponetInDirection(ret[0], d);
|
int o = opponetInDirection(ret[MOVE_TILE_ID], d);
|
||||||
if (s >= 0 && s < smin) smin = s;
|
if (s >= 0 && s < smin) smin = s;
|
||||||
if (o >= 0 && o < omin) omin = o;
|
if (o >= 0 && o < omin) omin = o;
|
||||||
}
|
}
|
||||||
// update path
|
// update path
|
||||||
Integer[] p = {
|
Integer[] p = {
|
||||||
ret[0], dir, moveFlag, supplyFlag,
|
ret[MOVE_TILE_ID], ret[MOVE_DICE], moveFlag, supplyFlag,
|
||||||
dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
|
dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
|
||||||
(smin != DirRange.End)? smin:Const.noSupply, (omin != DirRange.End)? omin:Const.noOpponent
|
(smin != DirRange.End)? smin:Const.noSupply, (omin != DirRange.End)? omin:Const.noOpponent
|
||||||
};
|
};
|
||||||
@ -197,10 +202,10 @@ class HeuristicPlayer extends Player {
|
|||||||
else
|
else
|
||||||
System.out.println("");
|
System.out.println("");
|
||||||
// extra prints for heuristic
|
// extra prints for heuristic
|
||||||
if (last[8] != Const.noSupply) System.out.println(" supply distance =" + last[8]);
|
if (last[8] != Const.noSupply) System.out.println(" supply =" + last[8]);
|
||||||
else System.out.println(" supply distance = blind");
|
else System.out.println(" supply = blind");
|
||||||
if (last[9] != Const.noOpponent) System.out.println(" opponent distance =" + last[9]);
|
if (last[9] != Const.noOpponent) System.out.println(" opponent =" + last[9]);
|
||||||
else System.out.println(" opponent distance = blind");
|
else System.out.println(" opponent = blind");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
388
src/host/labyrinth/MinMaxPlayer.java
Normal file
388
src/host/labyrinth/MinMaxPlayer.java
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
/**
|
||||||
|
* @file MinMaxPlayer.java
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
* Anastasia Foti AEM:8959
|
||||||
|
* <anastaskf@ece.auth.gr>
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
* Christos Choutouridis AEM:8997
|
||||||
|
* <cchoutou@ece.auth.gr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package host.labyrinth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* This class represents the game's minimax player.
|
||||||
|
*/
|
||||||
|
class MinMaxPlayer extends Player {
|
||||||
|
|
||||||
|
/** @name Constructors */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new player and put him at the row-column coordinates
|
||||||
|
* @param name The name of the player
|
||||||
|
* @param champion Flag to indicate if a player is a `champion`
|
||||||
|
* @param board Reference to the board of the game
|
||||||
|
* @param row The row coordinate of initial player position
|
||||||
|
* @param column The column coordinate of initial player's position
|
||||||
|
*/
|
||||||
|
public MinMaxPlayer(String name, boolean champion, Board board, int row, int column) throws Exception {
|
||||||
|
super(name, champion, board, row, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new player and put him at the row-column coordinates
|
||||||
|
* @param name The name of the player
|
||||||
|
* @param champion Flag to indicate if a player is a `champion`
|
||||||
|
* @param board Reference to the board of the game
|
||||||
|
* @param tileId The tileId coordinate of player's initial position
|
||||||
|
*/
|
||||||
|
public MinMaxPlayer(String name, boolean champion, Board board, int tileId) throws Exception {
|
||||||
|
super(name, champion, board, tileId);
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
/** @name Board's main application interface */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to get the distance of a possible supply in some direction
|
||||||
|
* @param currentPos The current position of the player
|
||||||
|
* @param direction The direction to check
|
||||||
|
* @param board Reference to the Board object to use
|
||||||
|
*
|
||||||
|
* @return The distance or Const.noView
|
||||||
|
*/
|
||||||
|
int supplyInDirection(int currentPos, int direction, Board board) {
|
||||||
|
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
||||||
|
|
||||||
|
for (int i=0 ; i<=Const.viewDistance ; ++i) {
|
||||||
|
if (board.hasSupply(pos.getId()))
|
||||||
|
return i;
|
||||||
|
if (board.isWalkable(pos.getId(), direction))
|
||||||
|
pos = new Position(pos.getRow(), pos.getCol(), direction);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Const.noView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to get the distance of a possible opponent in some direction
|
||||||
|
* @param currentPos The current position of the player
|
||||||
|
* @param direction The direction to check
|
||||||
|
* @param board Reference to the Board object to use
|
||||||
|
*
|
||||||
|
* @return The distance or Const.noView
|
||||||
|
*/
|
||||||
|
int opponetInDirection(int currentPos, int direction, Board board) {
|
||||||
|
Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
|
||||||
|
int[] opp = board.getOpponentMove(playerId);
|
||||||
|
|
||||||
|
for (int i=0 ; i<=Const.viewDistance ; ++i) {
|
||||||
|
if (opp[MOVE_TILE_ID] == pos.getId())
|
||||||
|
return i;
|
||||||
|
if (board.isWalkable(pos.getId(), direction))
|
||||||
|
pos = new Position(pos.getRow(), pos.getCol(), direction);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Const.noView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the main move evaluation function.
|
||||||
|
*
|
||||||
|
* @param currentPos The current position of the player (before the move to evaluate)
|
||||||
|
* @param direction The direction (a.k.a. the move) to evaluate
|
||||||
|
* @param board Reference to the Board object to use
|
||||||
|
* @return A signed real number. The higher the output, the higher the evaluation.
|
||||||
|
*/
|
||||||
|
double evaluate (int currentPos, int direction, Board board) {
|
||||||
|
Position next = new Position (Position.toRow(currentPos), Position.toCol(currentPos), direction);
|
||||||
|
|
||||||
|
int preOpDist = opponetInDirection (currentPos, direction, board);
|
||||||
|
int preSupDist = supplyInDirection(currentPos, direction, board);
|
||||||
|
int postOpDist = opponetInDirection (next.getId(), direction, board);
|
||||||
|
int postSupDist = supplyInDirection(next.getId(), direction, board);
|
||||||
|
|
||||||
|
return ((preSupDist != Const.noView) ? Const.preMoveFactor *(1.0/(preSupDist+1) * Const.supplyFactor) : 0)
|
||||||
|
- ((preOpDist != Const.noView) ? Const.preMoveFactor *(1.0/(preOpDist+1) * Const.opponentFactor) : 0)
|
||||||
|
+ ((postSupDist != Const.noView)? Const.postMoveFactor*(1.0/(preSupDist+1) * Const.supplyFactor) : 0)
|
||||||
|
- ((postOpDist != Const.noView) ? Const.postMoveFactor*(1.0/(preOpDist+1) * Const.opponentFactor) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the minimax algorithm and return a reference to selected move
|
||||||
|
* @param node The root node to start
|
||||||
|
* @return Reference to the selected move
|
||||||
|
*/
|
||||||
|
Node chooseMinMaxMove(Node node) {
|
||||||
|
node.setNodeEvaluation(maxValue(node));
|
||||||
|
return node.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the best possible move to return
|
||||||
|
* @param currentPos Player's current position to the board
|
||||||
|
* @return The move array
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* This function always return a new move.
|
||||||
|
*/
|
||||||
|
int[] getNextMove(int currentPos) {
|
||||||
|
Node root = new Node (board);
|
||||||
|
int [] opp = board.getOpponentMove(playerId);
|
||||||
|
|
||||||
|
createMySubtree(currentPos, opp[MOVE_TILE_ID], root, root.getNodeDepth()+1);
|
||||||
|
|
||||||
|
return chooseMinMaxMove(root).getNodeMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinMaxPlayer's move.
|
||||||
|
*
|
||||||
|
* A player of this kind cheats. He does not throw a dice to get a direction. In contrary he
|
||||||
|
* calculates his next move very carefully.
|
||||||
|
* If the player is a champion then he also picks up a possible supply from the tile.
|
||||||
|
*
|
||||||
|
* @param id The id of the starting tile.
|
||||||
|
* @return An array containing player's final position and possible supply of that position.
|
||||||
|
* The array format is:
|
||||||
|
* <ul>
|
||||||
|
* <li> int[0]: The tileId of the final player's position.
|
||||||
|
* <li> int[1]: The row of the final player's position.
|
||||||
|
* <li> int[2]: The column of the final player's position.
|
||||||
|
* <li> int[3]: The dice/direction of the move.
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int[] move(int id) {
|
||||||
|
// Initialize return array with the current data
|
||||||
|
int[] ret = getNextMove(id);
|
||||||
|
y = Position.toRow(ret[MOVE_TILE_ID]);
|
||||||
|
x = Position.toCol(ret[MOVE_TILE_ID]);
|
||||||
|
|
||||||
|
int supplyFlag =0, moveFlag =1;
|
||||||
|
// In case of a champion player, try also to pick a supply
|
||||||
|
if (champion && (board.tryPickSupply(ret[MOVE_TILE_ID]) != Const.noSupply)) {
|
||||||
|
++score; // keep score
|
||||||
|
++supplyFlag;
|
||||||
|
}
|
||||||
|
++dirCounter[ret[MOVE_DICE]]; // update direction counters
|
||||||
|
board.updateMove(ret, playerId);
|
||||||
|
|
||||||
|
// Update supply and opponent distance
|
||||||
|
int smin =Const.noView, omin =Const.noView;
|
||||||
|
for (int d = DirRange.Begin ; d<DirRange.End ; d += DirRange.Step) {
|
||||||
|
int s = supplyInDirection (ret[MOVE_TILE_ID], d, board);
|
||||||
|
int o = opponetInDirection(ret[MOVE_TILE_ID], d, board);
|
||||||
|
if (s < smin) smin = s;
|
||||||
|
if (o < omin) omin = o;
|
||||||
|
}
|
||||||
|
// update path
|
||||||
|
Integer[] p = {
|
||||||
|
ret[MOVE_TILE_ID], ret[MOVE_DICE], moveFlag, supplyFlag,
|
||||||
|
dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
|
||||||
|
smin, omin
|
||||||
|
};
|
||||||
|
path.add(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints round information for the player
|
||||||
|
*/
|
||||||
|
void statistics() {
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
Integer[] last = path.get(path.size()-1);
|
||||||
|
String who = String.format("%12s", name);
|
||||||
|
System.out.print(who + ": score[" + score + "]" + ", dice =" + last[1] + ", tileId =" + last[0] + " (" + Position.toRow(last[0]) + ", " + Position.toCol(last[0]) + ")");
|
||||||
|
if (last[2] == 0)
|
||||||
|
System.out.println(" *Can not move.");
|
||||||
|
else if (last[3] != 0)
|
||||||
|
System.out.println(" *Found a supply.");
|
||||||
|
else
|
||||||
|
System.out.println("");
|
||||||
|
// extra prints for minimax player
|
||||||
|
if (last[8] != Const.noView) System.out.println(" supply =" + last[8]);
|
||||||
|
else System.out.println(" supply = blind");
|
||||||
|
if (last[9] != Const.noView) System.out.println(" opponent =" + last[9]);
|
||||||
|
else System.out.println(" opponent = blind");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints final statistics for the player
|
||||||
|
*/
|
||||||
|
void final_statistics () {
|
||||||
|
String who = String.format("%12s", name);
|
||||||
|
System.out.println();
|
||||||
|
System.out.println(who + ": score[" + score + "]");
|
||||||
|
System.out.println(" Moves up: " + dirCounter[Direction.UP]);
|
||||||
|
System.out.println(" Moves right: " + dirCounter[Direction.RIGHT]);
|
||||||
|
System.out.println(" Moves down: " + dirCounter[Direction.DOWN]);
|
||||||
|
System.out.println(" Moves left: " + dirCounter[Direction.LEFT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** @name Minimax algorithm related part */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the previous direction of the player
|
||||||
|
* @param parent Reference to previous nNode
|
||||||
|
* @return The previous direction if exist, else return Direction.NONE
|
||||||
|
*/
|
||||||
|
private int prevDirection(Node parent) {
|
||||||
|
if (parent != null && parent.getParent() != null)
|
||||||
|
return parent.getParent().getNodeMove()[MOVE_DICE];
|
||||||
|
return Direction.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simulated move in a copy of the bard.
|
||||||
|
*
|
||||||
|
* @param board The board on witch we simulate the move
|
||||||
|
* @param currentPos The current position of the player to the @c board
|
||||||
|
* @param dir The direction of the move
|
||||||
|
* @param champion Flag to indicate if the player is champion or not
|
||||||
|
* @return The move array
|
||||||
|
*/
|
||||||
|
private int[] dryMove (Board board, int currentPos, int dir, boolean champion) {
|
||||||
|
int[] ret = new int[MOVE_DATA_SIZE];
|
||||||
|
Position p = new Position(Position.toRow(currentPos), Position.toCol(currentPos), dir);
|
||||||
|
ret[MOVE_TILE_ID] = p.getId();
|
||||||
|
ret[MOVE_ROW] = p.getRow();
|
||||||
|
ret[MOVE_COLUMN] = p.getCol();
|
||||||
|
ret[MOVE_DICE] = dir;
|
||||||
|
|
||||||
|
board.updateMove(ret, (champion) ? playerId : board.getOpponentId(playerId));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 currentPos The tile of MinMax player
|
||||||
|
* @param oppCurrentPos The tile of the opponent
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Even though unnecessary we calculate the evaluation for every node and not only for the leafs.
|
||||||
|
* This follows the exercise instructions. We could also rely on lazy evaluation of "evaluation()"
|
||||||
|
* and use AB pruning but the depth of the tree is not worth the try.
|
||||||
|
*/
|
||||||
|
private void createMySubtree (int currentPos, int oppCurrentPos, Node parent, int depth) {
|
||||||
|
ShuffledRange dirs = new ShuffledRange(DirRange.Begin, DirRange.End, DirRange.Step);
|
||||||
|
int [] nodeMove;
|
||||||
|
|
||||||
|
for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get()) {
|
||||||
|
if ((dir != Direction.opposite(prevDirection(parent)))
|
||||||
|
&& parent.getNodeBoard().isWalkable(currentPos, dir)) {
|
||||||
|
Board nodeBoard = new Board (parent.getNodeBoard()); // clone board
|
||||||
|
double eval = evaluate (currentPos, dir, nodeBoard); // evaluate the move
|
||||||
|
nodeMove = dryMove (nodeBoard, currentPos, dir, true); // simulate the move
|
||||||
|
// make child Node
|
||||||
|
Node child = new Node (parent, depth, nodeMove, nodeBoard, eval);
|
||||||
|
parent.addChild(child); // add child to tree
|
||||||
|
createOppSubtree (nodeMove[MOVE_TILE_ID], oppCurrentPos, child, depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 currentPos The tile of MinMax player
|
||||||
|
* @param oppCurrentPos The tile of the opponent
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Even though unnecessary we calculate the evaluation for every node and not only for the leafs.
|
||||||
|
* This follows the exercise instructions. We could also rely on lazy evaluation of "evaluation()"
|
||||||
|
* and use AB pruning but the depth of the tree is not worth the try.
|
||||||
|
*/
|
||||||
|
private void createOppSubtree (int currentPos, int oppCurrentPos, Node parent, int depth) {
|
||||||
|
ShuffledRange dirs = new ShuffledRange(DirRange.Begin, DirRange.End, DirRange.Step);
|
||||||
|
int [] nodeMove;
|
||||||
|
|
||||||
|
for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get()) {
|
||||||
|
if ((dir != Direction.opposite(prevDirection(parent)))
|
||||||
|
&& parent.getNodeBoard().isWalkable(oppCurrentPos, dir)) {
|
||||||
|
Board nodeBoard = new Board(parent.getNodeBoard()); // clone board
|
||||||
|
nodeMove = dryMove (nodeBoard, oppCurrentPos, dir, false); // simulate move
|
||||||
|
Position init = new Position( // evaluate from "My" perspective the move
|
||||||
|
parent.getNodeMove()[MOVE_ROW],
|
||||||
|
parent.getNodeMove()[MOVE_COLUMN],
|
||||||
|
Direction.opposite(parent.getNodeMove()[MOVE_DICE])
|
||||||
|
);
|
||||||
|
double eval = evaluate(init.getId(), parent.getNodeMove()[MOVE_DICE], nodeBoard);
|
||||||
|
// make child Node
|
||||||
|
Node child = new Node (parent, depth, nodeMove, nodeBoard, eval);
|
||||||
|
parent.addChild(child); // add child to tree
|
||||||
|
if (depth < Const.minimaxTreeDepth) {
|
||||||
|
createMySubtree (currentPos, nodeMove[MOVE_TILE_ID], child, depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Minimax recursive function for the maximizing part.
|
||||||
|
*
|
||||||
|
* @param node The current Node
|
||||||
|
* @return The selected Node
|
||||||
|
*/
|
||||||
|
private double maxValue (Node node) {
|
||||||
|
if (node.getChildren() == null) {
|
||||||
|
node.setPath(node);
|
||||||
|
return node.getNodeEvaluation();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
double M = Double.NEGATIVE_INFINITY;
|
||||||
|
for (Node n : node.getChildren()) {
|
||||||
|
n.setNodeEvaluation(minValue(n)); // evaluation propagation
|
||||||
|
if (M < n.getNodeEvaluation()) {
|
||||||
|
M = n.getNodeEvaluation();
|
||||||
|
node.setPath(n); // path propagation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return M;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Minimax recursive function for the minimizing part.
|
||||||
|
*
|
||||||
|
* @param node The current Node
|
||||||
|
* @return The selected Node
|
||||||
|
*/
|
||||||
|
private double minValue (Node node) {
|
||||||
|
if (node.getChildren() == null) {
|
||||||
|
node.setPath(node);
|
||||||
|
return node.getNodeEvaluation();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
double m = Double.POSITIVE_INFINITY;
|
||||||
|
for (Node n : node.getChildren()) {
|
||||||
|
n.setNodeEvaluation(maxValue(n)); // evaluation propagation
|
||||||
|
if (m > n.getNodeEvaluation()) {
|
||||||
|
m = n.getNodeEvaluation();
|
||||||
|
node.setPath(n); // path propagation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
}
|
119
src/host/labyrinth/Node.java
Normal file
119
src/host/labyrinth/Node.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @file Node.java
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
* Anastasia Foti AEM:8959
|
||||||
|
* <anastaskf@ece.auth.gr>
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
* Christos Choutouridis AEM:8997
|
||||||
|
* <cchoutou@ece.auth.gr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package host.labyrinth;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node object for minimax tree.
|
||||||
|
*/
|
||||||
|
class Node {
|
||||||
|
|
||||||
|
/** @name Constructors */
|
||||||
|
/** @{ */
|
||||||
|
/** Null initialize constructor */
|
||||||
|
Node () { }
|
||||||
|
/** The main constructor for the Node */
|
||||||
|
Node (Node parent, int nodeDepth, int [] nodeMove, Board nodeBoard, double nodeEvaluation) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.children = null;
|
||||||
|
this.nodeDepth = nodeDepth;
|
||||||
|
this.nodeMove = nodeMove;
|
||||||
|
this.nodeBoard = nodeBoard;
|
||||||
|
this.nodeEvaluation = nodeEvaluation;
|
||||||
|
this.path = null;
|
||||||
|
}
|
||||||
|
/** 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;
|
||||||
|
this.path = null;
|
||||||
|
}
|
||||||
|
/**@} */
|
||||||
|
|
||||||
|
/** @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; }
|
||||||
|
/** get path */
|
||||||
|
Node getPath() { return path; }
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
}
|
||||||
|
/** set path */
|
||||||
|
void setPath (Node path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** @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 */
|
||||||
|
private Node path; /**< The minimax evaluation path */
|
||||||
|
/**@}*/
|
||||||
|
}
|
@ -19,6 +19,13 @@ import java.util.ArrayList;
|
|||||||
* This class represents the game's player
|
* This class represents the game's player
|
||||||
*/
|
*/
|
||||||
class Player {
|
class Player {
|
||||||
|
/** Helper variables to keep track of the move() return values @see move() */
|
||||||
|
static final int MOVE_DATA_SIZE = 4; /**< The move return data array size */
|
||||||
|
static final int MOVE_TILE_ID = 0; /**< Index of the tileId information of the move */
|
||||||
|
static final int MOVE_ROW = 1; /**< The index of row information */
|
||||||
|
static final int MOVE_COLUMN = 2; /**< The index of column information */
|
||||||
|
static final int MOVE_DICE = 3; /**< The index of dice information */
|
||||||
|
|
||||||
/** @name Constructors */
|
/** @name Constructors */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
|
|
||||||
@ -30,7 +37,7 @@ class Player {
|
|||||||
* @param row The row coordinate of initial player position
|
* @param row The row coordinate of initial player position
|
||||||
* @param column The column coordinate of initial player's position
|
* @param column The column coordinate of initial player's position
|
||||||
*/
|
*/
|
||||||
Player(String name, boolean champion, Board board, int row, int column) {
|
Player(String name, boolean champion, Board board, int row, int column) throws Exception {
|
||||||
this.playerId = board.generatePlayerId();
|
this.playerId = board.generatePlayerId();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.board = board;
|
this.board = board;
|
||||||
@ -38,7 +45,7 @@ class Player {
|
|||||||
this.x = column;
|
this.x = column;
|
||||||
this.y = row;
|
this.y = row;
|
||||||
this.champion = champion;
|
this.champion = champion;
|
||||||
this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is worst.
|
this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is the worst.
|
||||||
this.path = new ArrayList<Integer[]>();
|
this.path = new ArrayList<Integer[]>();
|
||||||
int[] m = {
|
int[] m = {
|
||||||
Position.toID(row, column), row, column, Const.noSupply
|
Position.toID(row, column), row, column, Const.noSupply
|
||||||
@ -53,7 +60,7 @@ class Player {
|
|||||||
* @param board Reference to the board of the game
|
* @param board Reference to the board of the game
|
||||||
* @param tileId The tileId coordinate of player's initial position
|
* @param tileId The tileId coordinate of player's initial position
|
||||||
*/
|
*/
|
||||||
Player(String name, boolean champion, Board board, int tileId) {
|
Player(String name, boolean champion, Board board, int tileId) throws Exception {
|
||||||
this.playerId = board.generatePlayerId();
|
this.playerId = board.generatePlayerId();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.board = board;
|
this.board = board;
|
||||||
@ -61,7 +68,7 @@ class Player {
|
|||||||
this.x = Position.toCol(tileId);
|
this.x = Position.toCol(tileId);
|
||||||
this.y = Position.toRow(tileId);
|
this.y = Position.toRow(tileId);
|
||||||
this.champion = champion;
|
this.champion = champion;
|
||||||
this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is worst.
|
this.dirCounter= new int[DirRange.End]; // yes we spoil some memory. Java is the worst.
|
||||||
this.path = new ArrayList<Integer[]>();
|
this.path = new ArrayList<Integer[]>();
|
||||||
int[] m = {
|
int[] m = {
|
||||||
tileId, Position.toRow(tileId), Position.toCol(tileId), Const.noSupply
|
tileId, Position.toRow(tileId), Position.toCol(tileId), Const.noSupply
|
||||||
@ -87,37 +94,39 @@ class Player {
|
|||||||
* <li> int[0]: The tileId of the final player's position.
|
* <li> int[0]: The tileId of the final player's position.
|
||||||
* <li> int[1]: The row of the final player's position.
|
* <li> int[1]: The row of the final player's position.
|
||||||
* <li> int[2]: The column of the final player's position.
|
* <li> int[2]: The column of the final player's position.
|
||||||
* <li> int[1]: The supplyId in case player picked one (Const.noSupply otherwise).
|
* <li> int[3]: The dice/direction of the move.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
int[] move(int id) {
|
int[] move(int id) {
|
||||||
// Initialize return array with the current data
|
// Initialize return array with the current data
|
||||||
int[] ret = new int[Const.moveItems];
|
int[] ret = new int[MOVE_DATA_SIZE];
|
||||||
ret[0] = id;
|
ret[MOVE_TILE_ID] = id;
|
||||||
ret[1] = Position.toRow(id);
|
ret[MOVE_ROW] = Position.toRow(id);
|
||||||
ret[2] = Position.toCol(id);
|
ret[MOVE_COLUMN] = Position.toCol(id);
|
||||||
ret[3] = Const.noSupply;
|
ret[MOVE_DICE] = Direction.NONE;
|
||||||
int supplyFlag =0, moveFlag =0;
|
int supplyFlag =0, moveFlag =0;
|
||||||
|
|
||||||
int diceDirection = board.dice(); // throw the dice
|
int diceDirection;
|
||||||
if (board.isWalkable(id, diceDirection)) { // The result is walkable
|
do
|
||||||
moveFlag =1; // mark the successful move
|
diceDirection = board.dice(); // throw the dice
|
||||||
// Get next tile
|
while (!board.isWalkable(id, diceDirection));
|
||||||
Position next = new Position(Position.toRow(id), Position.toCol(id), diceDirection);
|
moveFlag =1; // mark the successful move
|
||||||
ret[0] = next.getId(); // Update player's and return data
|
// Get next tile
|
||||||
ret[1] = y = next.getRow();
|
Position next = new Position(Position.toRow(id), Position.toCol(id), diceDirection);
|
||||||
ret[2] = x = next.getCol();
|
ret[MOVE_TILE_ID] = next.getId(); // Update move's return data
|
||||||
// In case of a champion player, try also to pick a supply
|
ret[MOVE_ROW] = y = next.getRow();
|
||||||
if (champion && (ret[3] = board.tryPickSupply(next.getId())) != Const.noSupply) {
|
ret[MOVE_COLUMN] = x = next.getCol();
|
||||||
supplyFlag =1; // mark the successful supply pickup
|
ret[MOVE_DICE] = diceDirection;
|
||||||
++score; // keep score
|
// In case of a champion player, try also to pick a supply
|
||||||
}
|
if (champion && (board.tryPickSupply(next.getId()) != Const.noSupply)) {
|
||||||
++dirCounter[diceDirection]; // update direction counters
|
supplyFlag =1; // mark the successful supply pickup
|
||||||
board.updateMove(ret, playerId);
|
++score; // keep score
|
||||||
}
|
}
|
||||||
|
++dirCounter[diceDirection]; // update direction counters
|
||||||
|
board.updateMove(ret, playerId);
|
||||||
// update path
|
// update path
|
||||||
Integer[] p = {
|
Integer[] p = {
|
||||||
ret[0], diceDirection, moveFlag, supplyFlag,
|
ret[MOVE_TILE_ID], diceDirection, moveFlag, supplyFlag,
|
||||||
dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
|
dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
|
||||||
Const.noSupply, Const.noOpponent
|
Const.noSupply, Const.noOpponent
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user