|
|
@@ -15,13 +15,23 @@ import java.util.*; |
|
|
|
*/
|
|
|
|
public class HeuristicPlayer
|
|
|
|
extends Player {
|
|
|
|
// evaluate configuration
|
|
|
|
static final double FACTOR_TILE = 0.15;
|
|
|
|
static final double FACTOR_FWD_STEP = 0.55;
|
|
|
|
static final double FACTOR_BACK_STEP = -1.0;
|
|
|
|
static final double FACTOR_UP_POINTS = 0.3;
|
|
|
|
static final double FACTOR_DWN_POINTS= -1.0;
|
|
|
|
static final double FACTOR_INIT_EVAL = 1.0;
|
|
|
|
static final double FACTOR_ROUND = -1.0;
|
|
|
|
static final double FACTOR_GAME = 10.0;
|
|
|
|
|
|
|
|
/** @name Constructors */
|
|
|
|
/** @{ */
|
|
|
|
/** Default doing nothing constructor */
|
|
|
|
public HeuristicPlayer() {
|
|
|
|
super ();
|
|
|
|
path = new ArrayList<Integer[]>();
|
|
|
|
path = new ArrayList<Integer[]>();
|
|
|
|
evalData = new EvalData[board.getN() * board.getM() +1];
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @brief The main constructor
|
|
|
@@ -33,7 +43,8 @@ public class HeuristicPlayer |
|
|
|
*/
|
|
|
|
HeuristicPlayer (int playerId, String name, Board board) {
|
|
|
|
super (playerId, name, board);
|
|
|
|
path = new ArrayList<Integer[]>();
|
|
|
|
path = new ArrayList<Integer[]>();
|
|
|
|
evalData = new EvalData[board.getN() * board.getM() +1];
|
|
|
|
}
|
|
|
|
/* @} */
|
|
|
|
|
|
|
@@ -62,19 +73,10 @@ public class HeuristicPlayer |
|
|
|
*/
|
|
|
|
@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;
|
|
|
|
|
|
|
|
// Evaluate each possible dice result and find the better one
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
roll = evalProcess(tile);
|
|
|
|
// Do the move and get the move data
|
|
|
|
Integer[] move_data = Arrays.stream(move (tile, roll, true))
|
|
|
|
.boxed()
|
|
|
@@ -119,22 +121,105 @@ public class HeuristicPlayer |
|
|
|
super.statistics(verbose, sum);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int evalProcess (int tile) {
|
|
|
|
int[] check = new int[MOVE_DATA_SIZE];
|
|
|
|
int begin;
|
|
|
|
int end = board.getN() * board.getM();
|
|
|
|
int roll;
|
|
|
|
EvalData e = new EvalData();
|
|
|
|
|
|
|
|
for (int i =0 ; i<=end ; ++i) {
|
|
|
|
evalData[i] = new EvalData();
|
|
|
|
evalData[i].evaluation = Double.NEGATIVE_INFINITY;
|
|
|
|
}
|
|
|
|
for (begin =tile ; begin < end ; ++begin) {
|
|
|
|
if ((board.checkLadder(begin, false) != begin) ||
|
|
|
|
(board.checkSnake(begin) != begin))
|
|
|
|
continue;
|
|
|
|
int initRound = evalData[begin].round;
|
|
|
|
double initEval = evalData[begin].evaluation;
|
|
|
|
for (roll = 1 ; roll <= 6 ; ++roll) {
|
|
|
|
check = move (begin, roll, false);
|
|
|
|
e.game = _saturate (check);
|
|
|
|
e.round = initRound +1;
|
|
|
|
e.from = begin;
|
|
|
|
e.roll = roll;
|
|
|
|
e.steps = check[MOVE_STEPS_IDX];
|
|
|
|
e.points = check[MOVE_POINTS_IDX];
|
|
|
|
e.evaluation = _evalFormula (check[MOVE_TILE_IDX], e.steps, e.points, e.round, initEval, e.game);
|
|
|
|
if (e.evaluation > evalData[check[MOVE_TILE_IDX]].evaluation) {
|
|
|
|
evalData[check[MOVE_TILE_IDX]].copy(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// find route back of the optimal path
|
|
|
|
e = evalData[board.getN() * board.getM()];
|
|
|
|
EvalData last = e;
|
|
|
|
while (e.from != tile) {
|
|
|
|
last = e;
|
|
|
|
e = evalData[e.from];
|
|
|
|
}
|
|
|
|
|
|
|
|
return last.roll; // return the first choice
|
|
|
|
}
|
|
|
|
|
|
|
|
double evaluate (int tile, int roll) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The main evaluation function
|
|
|
|
* @param tile The current tile of the player
|
|
|
|
* @param roll the roll to check
|
|
|
|
* @return The evaluation of the roll
|
|
|
|
*/
|
|
|
|
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];
|
|
|
|
private double _evalFormula (int tile, int steps, int points, int round, double initEval, boolean game) {
|
|
|
|
initEval = (initEval == Double.NEGATIVE_INFINITY) ? 0 : initEval;
|
|
|
|
return tile * FACTOR_TILE +
|
|
|
|
steps * ((steps>0) ? FACTOR_FWD_STEP : FACTOR_BACK_STEP) +
|
|
|
|
points * ((points>0) ? FACTOR_UP_POINTS : FACTOR_DWN_POINTS) +
|
|
|
|
initEval * FACTOR_INIT_EVAL +
|
|
|
|
round * FACTOR_ROUND +
|
|
|
|
((game) ? 1:0) * FACTOR_GAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean _saturate (int[] check) {
|
|
|
|
// make adjustments if game is finished
|
|
|
|
int tiles = board.getM() * board.getN();
|
|
|
|
boolean game = (check[MOVE_TILE_IDX] >= tiles) ? true : false;
|
|
|
|
|
|
|
|
if (check[MOVE_TILE_IDX]> tiles) {
|
|
|
|
check[MOVE_STEPS_IDX] -= check[MOVE_TILE_IDX] - tiles;
|
|
|
|
check[MOVE_TILE_IDX] = tiles;
|
|
|
|
}
|
|
|
|
return game;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @name Data members package access only */
|
|
|
|
/** @{ */
|
|
|
|
private ArrayList<Integer[]> path; /**< Players history as required */
|
|
|
|
private EvalData[] evalData;
|
|
|
|
/** @} */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class EvalData {
|
|
|
|
int round;
|
|
|
|
int from;
|
|
|
|
int roll;
|
|
|
|
int steps;
|
|
|
|
int points;
|
|
|
|
boolean game;
|
|
|
|
double evaluation;
|
|
|
|
EvalData () { }
|
|
|
|
|
|
|
|
void copy (EvalData e) {
|
|
|
|
round = e.round;
|
|
|
|
from = e.from;
|
|
|
|
roll = e.roll;
|
|
|
|
steps = e.steps;
|
|
|
|
points = e.points;
|
|
|
|
game = e.game;
|
|
|
|
evaluation = e.evaluation;
|
|
|
|
}
|
|
|
|
} |