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:
@@ -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>() {
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
114
test/model/comPlayer/SpeedTest.java
Normal file
114
test/model/comPlayer/SpeedTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user