From 43c591bf4a36f19204348d9816459a31787b482e Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Sun, 2 Dec 2018 19:44:46 +0200 Subject: [PATCH] A dynamic programming test --- src/net/hoo2/auth/dsproject/snake/Game.java | 12 +- .../auth/dsproject/snake/HeuristicPlayer.java | 121 +++++++++++++++--- 2 files changed, 109 insertions(+), 24 deletions(-) diff --git a/src/net/hoo2/auth/dsproject/snake/Game.java b/src/net/hoo2/auth/dsproject/snake/Game.java index 1f5f9a1..d551a86 100644 --- a/src/net/hoo2/auth/dsproject/snake/Game.java +++ b/src/net/hoo2/auth/dsproject/snake/Game.java @@ -269,13 +269,13 @@ public class Game { */ public static void main(String[] args) { // Current project requirements - int lines = 20; - int columns = 10; - int numOfSnakes = 3; - int numOfLadders = 3; - int numOfApples = 6; + int lines = 6; //20; + int columns = 6; //10; + int numOfSnakes = 1; //3; + int numOfLadders = 1; //3; + int numOfApples = 2; //6; int numOfPlayers = 2; - boolean verbose = false; + boolean verbose = true; // Print caption System.out.println("================== Snake Game =================="); diff --git a/src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java b/src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java index 0cf95aa..a32b6e7 100644 --- a/src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java +++ b/src/net/hoo2/auth/dsproject/snake/HeuristicPlayer.java @@ -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(); + path = new ArrayList(); + 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(); + path = new ArrayList(); + evalData = new EvalData[board.getN() * board.getM() +1]; } /* @} */ @@ -62,19 +73,10 @@ public class HeuristicPlayer */ @Override int getNextMove (int tile) { - Map moves = new HashMap(); - 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 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; + } +} \ No newline at end of file