From 3ba0db6ebdb9c355c0c938067201f7f38ba55158 Mon Sep 17 00:00:00 2001 From: Woody Folsom Date: Tue, 1 May 2012 22:24:02 -0400 Subject: [PATCH] All MoveGenerators default to 1 move lookahead. Made MoveGenerators protected for unit testing. Added unit test for some analysis of MoveGenerator speeds. Fixed MDP to consider all states where #turns = maxTurns terminal. --- .../core/probability/example/MDPFactory.java | 6 +- src/model/comPlayer/AlphaBetaComPlayer.java | 2 +- src/model/comPlayer/MinimaxComPlayer.java | 2 +- src/model/comPlayer/MonteCarloComPlayer.java | 2 +- src/model/comPlayer/Player.java | 2 +- .../generator/AlphaBetaMoveGenerator.java | 11 +- .../generator/MinimaxMoveGenerator.java | 15 ++- .../generator/MonteCarloMoveGenerator.java | 11 +- .../comPlayer/generator/MoveGenerator.java | 1 + .../generator/NeuralNetworkMoveGenerator.java | 5 +- .../generator/ValidMoveGenerator.java | 7 +- test/model/comPlayer/SpeedTest.java | 114 ++++++++++++++++++ 12 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 test/model/comPlayer/SpeedTest.java diff --git a/src/aima/core/probability/example/MDPFactory.java b/src/aima/core/probability/example/MDPFactory.java index ab21fb0..8520ede 100644 --- a/src/aima/core/probability/example/MDPFactory.java +++ b/src/aima/core/probability/example/MDPFactory.java @@ -33,7 +33,11 @@ public class MDPFactory { public static ActionsFunction, GridWorldAction> createActionsFunctionForTileGame( final GridWorld cw, int maxTiles, int maxScore) { final Set> terminals = new HashSet>(); - terminals.add(cw.getCellAt(maxTiles,maxScore)); + + for (int score = 1; score <= maxScore; score++) { + terminals.add(cw.getCellAt(maxTiles,score)); + } + //terminals.add(cw.getCellAt(maxTiles,maxScore)); ActionsFunction, GridWorldAction> af = new ActionsFunction, GridWorldAction>() { diff --git a/src/model/comPlayer/AlphaBetaComPlayer.java b/src/model/comPlayer/AlphaBetaComPlayer.java index 0e965de..576aa69 100644 --- a/src/model/comPlayer/AlphaBetaComPlayer.java +++ b/src/model/comPlayer/AlphaBetaComPlayer.java @@ -8,7 +8,7 @@ import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class AlphaBetaComPlayer implements Player { - private final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator(); + final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator(); @Override public void denyMove() { diff --git a/src/model/comPlayer/MinimaxComPlayer.java b/src/model/comPlayer/MinimaxComPlayer.java index 6189a6d..c5b520e 100644 --- a/src/model/comPlayer/MinimaxComPlayer.java +++ b/src/model/comPlayer/MinimaxComPlayer.java @@ -8,7 +8,7 @@ import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class MinimaxComPlayer implements Player { - private final MoveGenerator moveGenerator = new MinimaxMoveGenerator(); + final MoveGenerator moveGenerator = new MinimaxMoveGenerator(); public MinimaxComPlayer() { super(); diff --git a/src/model/comPlayer/MonteCarloComPlayer.java b/src/model/comPlayer/MonteCarloComPlayer.java index 2b78c73..0dcd6f8 100644 --- a/src/model/comPlayer/MonteCarloComPlayer.java +++ b/src/model/comPlayer/MonteCarloComPlayer.java @@ -8,7 +8,7 @@ import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class MonteCarloComPlayer implements Player { - private final MoveGenerator moveGenerator = new MonteCarloMoveGenerator(); + final MoveGenerator moveGenerator = new MonteCarloMoveGenerator(); @Override public void denyMove() { diff --git a/src/model/comPlayer/Player.java b/src/model/comPlayer/Player.java index 793c2cc..ff87e3c 100644 --- a/src/model/comPlayer/Player.java +++ b/src/model/comPlayer/Player.java @@ -29,4 +29,4 @@ public interface Player { public boolean isReady(); public void setGameGoal(GameGoal target); -} +} \ No newline at end of file diff --git a/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java b/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java index fc860eb..7396f9e 100644 --- a/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java +++ b/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java @@ -10,7 +10,7 @@ import model.SearchResult; public class AlphaBetaMoveGenerator implements MoveGenerator { private static final int DEFAULT_RECURSIVE_PLAYS = 1; - + private int lookahead = DEFAULT_RECURSIVE_PLAYS; private final BoardScorer scorer = new BoardScorer(); private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); @@ -18,10 +18,10 @@ public class AlphaBetaMoveGenerator implements MoveGenerator { public Move genMove(Board board, boolean asHuman) { if (!asHuman) { - return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, + return getMaxValue(board, asHuman, lookahead * 2, Integer.MIN_VALUE, Integer.MAX_VALUE).move; } else { - return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, + return getMinValue(board, asHuman, lookahead * 2, Integer.MIN_VALUE, Integer.MAX_VALUE).move; } } @@ -114,4 +114,9 @@ public class AlphaBetaMoveGenerator implements MoveGenerator { return bestResult; } + @Override + public boolean setLookahead(int lookahead) { + this.lookahead = lookahead; + return true; + } } \ No newline at end of file diff --git a/src/model/comPlayer/generator/MinimaxMoveGenerator.java b/src/model/comPlayer/generator/MinimaxMoveGenerator.java index 8752817..f339925 100644 --- a/src/model/comPlayer/generator/MinimaxMoveGenerator.java +++ b/src/model/comPlayer/generator/MinimaxMoveGenerator.java @@ -9,7 +9,8 @@ import model.Move; import model.SearchResult; public class MinimaxMoveGenerator implements MoveGenerator { - private static final int DEFAULT_RECURSIVE_PLAYS = 2; + private static final int DEFAULT_RECURSIVE_PLAYS = 1; + private int lookahead = DEFAULT_RECURSIVE_PLAYS; private final BoardScorer scorer = new BoardScorer(); private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); @@ -20,12 +21,12 @@ public class MinimaxMoveGenerator implements MoveGenerator { //have different types of moves. SearchResult searchResult; if (!asHuman) { - searchResult = getMaxValue(board, Move.NONE, asHuman, DEFAULT_RECURSIVE_PLAYS * 2); + searchResult = getMaxValue(board, Move.NONE, asHuman, lookahead * 2); } else { - searchResult = getMinValue(board, Move.NONE, asHuman, DEFAULT_RECURSIVE_PLAYS * 2); + searchResult = getMinValue(board, Move.NONE, asHuman, lookahead * 2); } - System.out.println(searchResult); + //System.out.println(searchResult); return searchResult.move; } @@ -94,4 +95,10 @@ public class MinimaxMoveGenerator implements MoveGenerator { Move[] doNothing = new Move[] { Move.NONE }; return Arrays.asList(doNothing); } + + @Override + public boolean setLookahead(int lookahead) { + this.lookahead = lookahead; + return true; + } } diff --git a/src/model/comPlayer/generator/MonteCarloMoveGenerator.java b/src/model/comPlayer/generator/MonteCarloMoveGenerator.java index c5c7ddf..8df4a3c 100644 --- a/src/model/comPlayer/generator/MonteCarloMoveGenerator.java +++ b/src/model/comPlayer/generator/MonteCarloMoveGenerator.java @@ -9,7 +9,8 @@ import model.Move; import model.SearchResult; public class MonteCarloMoveGenerator implements MoveGenerator { - private static final int DEFAULT_RECURSIVE_PLAYS = 3; + private static final int DEFAULT_RECURSIVE_PLAYS = 1; + private int lookahead = DEFAULT_RECURSIVE_PLAYS; private static final int MOVES_PER_LEVEL = 12; private final BoardScorer scorer = new BoardScorer(); @@ -18,7 +19,7 @@ public class MonteCarloMoveGenerator implements MoveGenerator { @Override public Move genMove(Board board, boolean asHuman) { - SearchResult bestResult = genMove(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2); + SearchResult bestResult = genMove(board, asHuman, lookahead * 2); return bestResult.move; } @@ -74,4 +75,10 @@ public class MonteCarloMoveGenerator implements MoveGenerator { Move[] doNothing = new Move[] { Move.NONE }; return Arrays.asList(doNothing); } + + @Override + public boolean setLookahead(int lookahead) { + this.lookahead = lookahead; + return true; + } } \ No newline at end of file diff --git a/src/model/comPlayer/generator/MoveGenerator.java b/src/model/comPlayer/generator/MoveGenerator.java index 1638d8c..6ed7b96 100644 --- a/src/model/comPlayer/generator/MoveGenerator.java +++ b/src/model/comPlayer/generator/MoveGenerator.java @@ -10,4 +10,5 @@ public interface MoveGenerator { public Move genMove(Board board, boolean asHuman); public List genMoves(Board board, boolean asHuman, int nMoves); + public boolean setLookahead(int lookahead); } \ No newline at end of file diff --git a/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java b/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java index 7e9cb75..5b0542c 100644 --- a/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java +++ b/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java @@ -94,5 +94,8 @@ public class NeuralNetworkMoveGenerator implements MoveGenerator { // Do nothing. return null; } - + @Override + public boolean setLookahead(int lookahead) { + return false; + } } \ No newline at end of file diff --git a/src/model/comPlayer/generator/ValidMoveGenerator.java b/src/model/comPlayer/generator/ValidMoveGenerator.java index f1e5109..ede31d8 100644 --- a/src/model/comPlayer/generator/ValidMoveGenerator.java +++ b/src/model/comPlayer/generator/ValidMoveGenerator.java @@ -39,4 +39,9 @@ public class ValidMoveGenerator implements MoveGenerator { return validMoves.subList(0, Math.min(validMoves.size(), nMoves)); } } -} + + @Override + public boolean setLookahead(int lookahead) { + return false; + } +} \ No newline at end of file diff --git a/test/model/comPlayer/SpeedTest.java b/test/model/comPlayer/SpeedTest.java new file mode 100644 index 0000000..a0a5059 --- /dev/null +++ b/test/model/comPlayer/SpeedTest.java @@ -0,0 +1,114 @@ +package model.comPlayer; + +import org.junit.Ignore; +import org.junit.Test; + +import model.Board; +import model.Board.TileColor; +import model.playerModel.PlayerModel; +import model.CellPointer; + +public class SpeedTest { + private static final Board board = new Board(); + private static final int nTestRounds = 10; + private static final int lookahead = 3; + + static { + board.playTile(new CellPointer(2,2), TileColor.BLUE); + } + + @Test + public void testRandom() { + long testTime = 0L; + + RandomComPlayer player = new RandomComPlayer(); + + PlayerModel model = new PlayerModel("test"); + + for (int testRound = 0; testRound < nTestRounds; testRound++) { + Board newBoard = new Board(board); + + long testStart = System.currentTimeMillis(); + player.getMove(newBoard, model); + long testEnd = System.currentTimeMillis(); + + testTime += testEnd - testStart; + } + + double avgTime = testTime / (nTestRounds * 1000.0); + + System.out.println("Average time for RandomMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime); + } + + @Test + public void testMonteCarlo() { + long testTime = 0L; + + MonteCarloComPlayer player = new MonteCarloComPlayer(); + player.moveGenerator.setLookahead(lookahead); + + PlayerModel model = new PlayerModel("test"); + + for (int testRound = 0; testRound < nTestRounds; testRound++) { + Board newBoard = new Board(board); + + long testStart = System.currentTimeMillis(); + player.getMove(newBoard, model); + long testEnd = System.currentTimeMillis(); + + testTime += testEnd - testStart; + } + + double avgTime = testTime / (nTestRounds * 1000.0); + + System.out.println("Average time for MonteCarloGenerator.genMove() over " + nTestRounds + " tests: " + avgTime); + } + + @Ignore + public void testMinimax() { + long testTime = 0L; + + MinimaxComPlayer player = new MinimaxComPlayer(); + player.moveGenerator.setLookahead(lookahead); + + PlayerModel model = new PlayerModel("test"); + + for (int testRound = 0; testRound < nTestRounds; testRound++) { + Board newBoard = new Board(board); + + long testStart = System.currentTimeMillis(); + player.getMove(newBoard, model); + long testEnd = System.currentTimeMillis(); + + testTime += testEnd - testStart; + } + + double avgTime = testTime / (nTestRounds * 1000.0); + + System.out.println("Average time for MinimaxMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime); + } + + @Test + public void testAlphaBeta() { + long testTime = 0L; + + AlphaBetaComPlayer player = new AlphaBetaComPlayer(); + player.moveGenerator.setLookahead(lookahead); + + PlayerModel model = new PlayerModel("test"); + + for (int testRound = 0; testRound < nTestRounds; testRound++) { + Board newBoard = new Board(board); + + long testStart = System.currentTimeMillis(); + player.getMove(newBoard, model); + long testEnd = System.currentTimeMillis(); + + testTime += testEnd - testStart; + } + + double avgTime = testTime / (nTestRounds * 1000.0); + + System.out.println("Average time for AlphaBetaMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime); + } +}