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.
This commit is contained in:
Woody Folsom
2012-05-01 22:24:02 -04:00
parent 924780baaf
commit 3ba0db6ebd
12 changed files with 162 additions and 16 deletions

View File

@@ -33,7 +33,11 @@ public class MDPFactory {
public static ActionsFunction<GridCell<Double>, GridWorldAction> createActionsFunctionForTileGame( public static ActionsFunction<GridCell<Double>, GridWorldAction> createActionsFunctionForTileGame(
final GridWorld<Double> cw, int maxTiles, int maxScore) { final GridWorld<Double> cw, int maxTiles, int maxScore) {
final Set<GridCell<Double>> terminals = new HashSet<GridCell<Double>>(); final Set<GridCell<Double>> terminals = new HashSet<GridCell<Double>>();
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<GridCell<Double>, GridWorldAction> af = new ActionsFunction<GridCell<Double>, GridWorldAction>() { ActionsFunction<GridCell<Double>, GridWorldAction> af = new ActionsFunction<GridCell<Double>, GridWorldAction>() {

View File

@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
import model.playerModel.PlayerModel; import model.playerModel.PlayerModel;
public class AlphaBetaComPlayer implements Player { public class AlphaBetaComPlayer implements Player {
private final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator(); final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator();
@Override @Override
public void denyMove() { public void denyMove() {

View File

@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
import model.playerModel.PlayerModel; import model.playerModel.PlayerModel;
public class MinimaxComPlayer implements Player { public class MinimaxComPlayer implements Player {
private final MoveGenerator moveGenerator = new MinimaxMoveGenerator(); final MoveGenerator moveGenerator = new MinimaxMoveGenerator();
public MinimaxComPlayer() { public MinimaxComPlayer() {
super(); super();

View File

@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
import model.playerModel.PlayerModel; import model.playerModel.PlayerModel;
public class MonteCarloComPlayer implements Player { public class MonteCarloComPlayer implements Player {
private final MoveGenerator moveGenerator = new MonteCarloMoveGenerator(); final MoveGenerator moveGenerator = new MonteCarloMoveGenerator();
@Override @Override
public void denyMove() { public void denyMove() {

View File

@@ -29,4 +29,4 @@ public interface Player {
public boolean isReady(); public boolean isReady();
public void setGameGoal(GameGoal target); public void setGameGoal(GameGoal target);
} }

View File

@@ -10,7 +10,7 @@ import model.SearchResult;
public class AlphaBetaMoveGenerator implements MoveGenerator { public class AlphaBetaMoveGenerator implements MoveGenerator {
private static final int DEFAULT_RECURSIVE_PLAYS = 1; private static final int DEFAULT_RECURSIVE_PLAYS = 1;
private int lookahead = DEFAULT_RECURSIVE_PLAYS;
private final BoardScorer scorer = new BoardScorer(); private final BoardScorer scorer = new BoardScorer();
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
@@ -18,10 +18,10 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
public Move genMove(Board board, boolean asHuman) { public Move genMove(Board board, boolean asHuman) {
if (!asHuman) { if (!asHuman) {
return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, return getMaxValue(board, asHuman, lookahead * 2,
Integer.MIN_VALUE, Integer.MAX_VALUE).move; Integer.MIN_VALUE, Integer.MAX_VALUE).move;
} else { } else {
return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, return getMinValue(board, asHuman, lookahead * 2,
Integer.MIN_VALUE, Integer.MAX_VALUE).move; Integer.MIN_VALUE, Integer.MAX_VALUE).move;
} }
} }
@@ -114,4 +114,9 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
return bestResult; return bestResult;
} }
@Override
public boolean setLookahead(int lookahead) {
this.lookahead = lookahead;
return true;
}
} }

View File

@@ -9,7 +9,8 @@ import model.Move;
import model.SearchResult; import model.SearchResult;
public class MinimaxMoveGenerator implements MoveGenerator { 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 BoardScorer scorer = new BoardScorer();
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
@@ -20,12 +21,12 @@ public class MinimaxMoveGenerator implements MoveGenerator {
//have different types of moves. //have different types of moves.
SearchResult searchResult; SearchResult searchResult;
if (!asHuman) { if (!asHuman) {
searchResult = getMaxValue(board, Move.NONE, asHuman, DEFAULT_RECURSIVE_PLAYS * 2); searchResult = getMaxValue(board, Move.NONE, asHuman, lookahead * 2);
} else { } 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; return searchResult.move;
} }
@@ -94,4 +95,10 @@ public class MinimaxMoveGenerator implements MoveGenerator {
Move[] doNothing = new Move[] { Move.NONE }; Move[] doNothing = new Move[] { Move.NONE };
return Arrays.asList(doNothing); return Arrays.asList(doNothing);
} }
@Override
public boolean setLookahead(int lookahead) {
this.lookahead = lookahead;
return true;
}
} }

View File

@@ -9,7 +9,8 @@ import model.Move;
import model.SearchResult; import model.SearchResult;
public class MonteCarloMoveGenerator implements MoveGenerator { 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 static final int MOVES_PER_LEVEL = 12;
private final BoardScorer scorer = new BoardScorer(); private final BoardScorer scorer = new BoardScorer();
@@ -18,7 +19,7 @@ public class MonteCarloMoveGenerator implements MoveGenerator {
@Override @Override
public Move genMove(Board board, boolean asHuman) { 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; return bestResult.move;
} }
@@ -74,4 +75,10 @@ public class MonteCarloMoveGenerator implements MoveGenerator {
Move[] doNothing = new Move[] { Move.NONE }; Move[] doNothing = new Move[] { Move.NONE };
return Arrays.asList(doNothing); return Arrays.asList(doNothing);
} }
@Override
public boolean setLookahead(int lookahead) {
this.lookahead = lookahead;
return true;
}
} }

View File

@@ -10,4 +10,5 @@ public interface MoveGenerator {
public Move genMove(Board board, boolean asHuman); public Move genMove(Board board, boolean asHuman);
public List<Move> genMoves(Board board, boolean asHuman, int nMoves); public List<Move> genMoves(Board board, boolean asHuman, int nMoves);
public boolean setLookahead(int lookahead);
} }

View File

@@ -94,5 +94,8 @@ public class NeuralNetworkMoveGenerator implements MoveGenerator {
// Do nothing. // Do nothing.
return null; return null;
} }
@Override
public boolean setLookahead(int lookahead) {
return false;
}
} }

View File

@@ -39,4 +39,9 @@ public class ValidMoveGenerator implements MoveGenerator {
return validMoves.subList(0, Math.min(validMoves.size(), nMoves)); return validMoves.subList(0, Math.min(validMoves.size(), nMoves));
} }
} }
}
@Override
public boolean setLookahead(int lookahead) {
return false;
}
}

View File

@@ -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);
}
}