From bb5990a04fbac3f2a75dce64d18076d8db75d950 Mon Sep 17 00:00:00 2001 From: cs6601 Date: Tue, 28 Aug 2012 10:40:37 -0400 Subject: [PATCH] Substantial refactoring to implement correct Naive, UCT Monte Carlo tree search methods. Removed unnecessary distinction between policy and tree search (tree search is a special kind of policy). Calculation of all valid moves / arbitrary sets of moves is now a seperate class, as it serves a different purpose than a policy. Introduced regression error in AlphaBeta test. --- src/cs6601/p1/GameController.java | 5 - .../p1/generator/AlphaBetaMoveGenerator.java | 168 ------------------ .../p1/generator/MonteCarloMoveGenerator.java | 109 ------------ src/cs6601/p1/generator/MoveGenerator.java | 13 -- .../woodyfolsom/msproj}/Command.java | 2 +- .../woodyfolsom/msproj}/CommandParser.java | 2 +- .../woodyfolsom/msproj}/GameBoard.java | 2 +- .../woodyfolsom/msproj}/GameConfig.java | 2 +- .../woodyfolsom/msproj/GameController.java | 5 + .../woodyfolsom/msproj}/GameScore.java | 2 +- .../woodyfolsom/msproj}/GameState.java | 7 +- .../p1 => net/woodyfolsom/msproj}/GoGame.java | 45 ++--- .../woodyfolsom/msproj}/GtpClient.java | 2 +- .../woodyfolsom/msproj}/LibertyCounter.java | 2 +- .../woodyfolsom/msproj}/StateEvaluator.java | 2 +- .../woodyfolsom/msproj}/TerritoryMarker.java | 2 +- .../msproj/ZobristHashGenerator.java | 27 +++ .../msproj/policy/ActionGenerator.java | 13 ++ .../woodyfolsom/msproj/policy/AlphaBeta.java | 144 +++++++++++++++ .../msproj/policy/GameTreeNode.java | 60 +++++++ .../woodyfolsom/msproj/policy/Minimax.java} | 42 ++--- .../woodyfolsom/msproj/policy/MonteCarlo.java | 61 +++++++ .../msproj/policy/MonteCarloTreeNode.java | 30 ++++ .../msproj/policy/MonteCarloUCT.java | 34 ++++ .../msproj/policy}/MoveCandidate.java | 4 +- src/net/woodyfolsom/msproj/policy/Policy.java | 10 ++ .../msproj/policy/RandomMovePolicy.java} | 11 +- .../msproj/policy}/ValidMoveGenerator.java | 24 +-- .../woodyfolsom/msproj}/CaptureTest.java | 8 +- .../woodyfolsom/msproj}/GameScoreTest.java | 4 +- .../woodyfolsom/msproj}/IllegalMoveTest.java | 5 +- .../woodyfolsom/msproj}/LegalMoveTest.java | 5 +- .../msproj}/StateEvaluatorTest.java | 10 +- .../msproj}/TerritoryFinderTest.java | 6 +- .../msproj/ZobristHashGeneratorTest.java | 17 ++ .../msproj/policy}/AlphaBetaTest.java | 44 ++--- .../msproj/policy}/MinimaxTest.java | 17 +- .../msproj/policy}/RandomTest.java | 23 +-- .../policy}/ValidMoveGeneratorTest.java | 12 +- 39 files changed, 550 insertions(+), 431 deletions(-) delete mode 100644 src/cs6601/p1/GameController.java delete mode 100644 src/cs6601/p1/generator/AlphaBetaMoveGenerator.java delete mode 100644 src/cs6601/p1/generator/MonteCarloMoveGenerator.java delete mode 100644 src/cs6601/p1/generator/MoveGenerator.java rename src/{cs6601/p1 => net/woodyfolsom/msproj}/Command.java (91%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/CommandParser.java (95%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GameBoard.java (95%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GameConfig.java (86%) create mode 100644 src/net/woodyfolsom/msproj/GameController.java rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GameScore.java (94%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GameState.java (95%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GoGame.java (73%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/GtpClient.java (94%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/LibertyCounter.java (95%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/StateEvaluator.java (92%) rename src/{cs6601/p1 => net/woodyfolsom/msproj}/TerritoryMarker.java (95%) create mode 100644 src/net/woodyfolsom/msproj/ZobristHashGenerator.java create mode 100644 src/net/woodyfolsom/msproj/policy/ActionGenerator.java create mode 100644 src/net/woodyfolsom/msproj/policy/AlphaBeta.java create mode 100644 src/net/woodyfolsom/msproj/policy/GameTreeNode.java rename src/{cs6601/p1/generator/MinimaxMoveGenerator.java => net/woodyfolsom/msproj/policy/Minimax.java} (68%) create mode 100644 src/net/woodyfolsom/msproj/policy/MonteCarlo.java create mode 100644 src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java create mode 100644 src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java rename src/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/MoveCandidate.java (67%) create mode 100644 src/net/woodyfolsom/msproj/policy/Policy.java rename src/{cs6601/p1/generator/RandomMoveGenerator.java => net/woodyfolsom/msproj/policy/RandomMovePolicy.java} (83%) rename src/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/ValidMoveGenerator.java (52%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/CaptureTest.java (88%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/GameScoreTest.java (85%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/IllegalMoveTest.java (92%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/LegalMoveTest.java (77%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/StateEvaluatorTest.java (89%) rename test/{cs6601/p1 => net/woodyfolsom/msproj}/TerritoryFinderTest.java (73%) create mode 100644 test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java rename test/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/AlphaBetaTest.java (60%) rename test/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/MinimaxTest.java (55%) rename test/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/RandomTest.java (66%) rename test/{cs6601/p1/generator => net/woodyfolsom/msproj/policy}/ValidMoveGeneratorTest.java (71%) diff --git a/src/cs6601/p1/GameController.java b/src/cs6601/p1/GameController.java deleted file mode 100644 index 9d201dd..0000000 --- a/src/cs6601/p1/GameController.java +++ /dev/null @@ -1,5 +0,0 @@ -package cs6601.p1; - -public class GameController { - -} \ No newline at end of file diff --git a/src/cs6601/p1/generator/AlphaBetaMoveGenerator.java b/src/cs6601/p1/generator/AlphaBetaMoveGenerator.java deleted file mode 100644 index e6a35e3..0000000 --- a/src/cs6601/p1/generator/AlphaBetaMoveGenerator.java +++ /dev/null @@ -1,168 +0,0 @@ -package cs6601.p1.generator; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.log4j.Logger; - -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; -import cs6601.p1.StateEvaluator; - -public class AlphaBetaMoveGenerator implements MoveGenerator { - private static final Logger LOGGER = Logger.getLogger(AlphaBetaMoveGenerator.class.getName()); - private static final int DEFAULT_RECURSIVE_PLAYS = 3; - private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); - - private String bestPick = MoveGenerator.PASS; - - @Override - public String genMove(GameConfig gameConfig, GameState gameState, - String initialColor) { - - int alpha = Integer.MIN_VALUE; - int beta = Integer.MAX_VALUE; - - if ("b".equals(initialColor)) { - getMaxValue(gameConfig,gameState,initialColor,false,DEFAULT_RECURSIVE_PLAYS*2,alpha,beta); - return bestPick; - } else if ("w".equals(initialColor)) { - getMinValue(gameConfig,gameState,initialColor,false,DEFAULT_RECURSIVE_PLAYS*2,alpha,beta); - return bestPick; - } else { - return MoveGenerator.PASS; - } - } - - private int getMaxValue(GameConfig gameConfig, GameState gameState, - String initialColor, boolean playAsOpponent, int recursionLevel, int alpha, int beta) { - if (terminalTest(recursionLevel)) { - return getUtility(gameConfig,gameState); - } - - String colorPlaying = getColorToPlay(initialColor, playAsOpponent); - - List validMoves = validMoveGenerator.genMoves(gameConfig, - gameState, colorPlaying, MoveGenerator.ALL_MOVES); - - int value = Integer.MIN_VALUE; - - //Map firstMovesByScore = new HashMap (); - - for (String nextMove : validMoves) { - GameState nextState = new GameState(gameState); - - if (!nextState.playStone(colorPlaying, nextMove)) { - throw new RuntimeException("Illegal move attempted during search!"); - } - - int minValue = getMinValue(gameConfig, nextState, - initialColor, !playAsOpponent, recursionLevel-1, alpha, beta); - //value = Math.max(value, minResult); - if (minValue > value) { - value = minValue; - if (recursionLevel == DEFAULT_RECURSIVE_PLAYS * 2) { - bestPick = nextMove; - } - } - /// - //if (recursionLevel == 2 * DEFAULT_RECURSIVE_PLAYS) { - // firstMovesByScore.put(value, nextMove); - //} - /// - if (value >= beta) { - return value; - } - alpha = Math.max(alpha,value); - } - - return value; - } - - private int getMinValue(GameConfig gameConfig, GameState gameState, - String initialColor, boolean playAsOpponent, int recursionLevel, int alpha, int beta) { - if (terminalTest(recursionLevel)) { - return getUtility(gameConfig,gameState); - } - - String colorPlaying = getColorToPlay(initialColor, playAsOpponent); - - List validMoves = validMoveGenerator.genMoves(gameConfig, - gameState, colorPlaying, MoveGenerator.ALL_MOVES); - - int value = Integer.MAX_VALUE; - - //Map firstMovesByScore = new HashMap (); - - for (String nextMove : validMoves) { - GameState nextState = new GameState(gameState); - - if (!nextState.playStone(colorPlaying, nextMove)) { - throw new RuntimeException("Illegal move attempted during search!"); - } - - int maxValue = getMaxValue(gameConfig, nextState, - initialColor, !playAsOpponent, recursionLevel-1, alpha, beta); - //value = Math.min(value, maxValue); - if (maxValue < value) { - value = maxValue; - if (recursionLevel == 2 * DEFAULT_RECURSIVE_PLAYS) { - //firstMovesByScore.put(value, nextMove); - bestPick = nextMove; - } - } - /// - //if (recursionLevel == 2 * DEFAULT_RECURSIVE_PLAYS) { - // firstMovesByScore.put(value, nextMove); - //} - /// - if (value <= alpha) { - return value; - } - beta = Math.min(beta,value); - } - - //if (recursionLevel == DEFAULT_RECURSIVE_PLAYS * 2) { - // bestPick = firstMovesByScore.get(value); - //} - - return value; - } - - private boolean terminalTest(int recursionLevel) { - return recursionLevel < 1; - } - - private int getUtility(GameConfig gameConfig, GameState gameState) { - StateEvaluator stateEvaluator = new StateEvaluator(gameConfig); - return stateEvaluator.scoreGame(gameState).getAggregateScore(); - } - - private String getColorToPlay(String color, boolean playAsOpponent) { - if (playAsOpponent) { - if ("w".equals(color)) { - return "b"; - } else if ("b".equals(color)) { - return "w"; - } else { - return "?"; // invalid color will cause randomMoveGenerator to - // PASS - } - } else { - return color; - } - } - - /** - * AlphaBetaMoveGenerator2 does not support this method. - */ - @Override - public List genMoves(GameConfig gameConfig, GameState gameState, - String color, int nMoves) { - String[] pass = new String[] {PASS}; - LOGGER.info("Minimax genMoves() stub returning [PASS]"); - return Arrays.asList(pass); - } -} diff --git a/src/cs6601/p1/generator/MonteCarloMoveGenerator.java b/src/cs6601/p1/generator/MonteCarloMoveGenerator.java deleted file mode 100644 index 22d3bc8..0000000 --- a/src/cs6601/p1/generator/MonteCarloMoveGenerator.java +++ /dev/null @@ -1,109 +0,0 @@ -package cs6601.p1.generator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import cs6601.p1.GameConfig; -import cs6601.p1.GameScore; -import cs6601.p1.GameState; -import cs6601.p1.StateEvaluator; - -public class MonteCarloMoveGenerator implements MoveGenerator { - //private static final Logger LOGGER = Logger - // .getLogger(MonteCarloMoveGenerator.class.getName()); - - private static final int DEFAULT_RECURSIVE_PLAYS = 3; - private static final int DEFAULT_PLAYS_PER_LEVEL = 10; - //private static final int MAX_RANDOM_TRIES = 10; - - private final RandomMoveGenerator randomMoveGenerator = new RandomMoveGenerator(); - - @Override - public String genMove(GameConfig gameConfig, GameState gameState, - String color) { - MoveCandidate moveCandidate = findBestMonteCarloResult( - DEFAULT_RECURSIVE_PLAYS * 2, DEFAULT_PLAYS_PER_LEVEL, - gameConfig, gameState, color, false, PASS); - - return moveCandidate.move; - } - - private MoveCandidate findBestMonteCarloResult(int recursionLevels, - int playsPerLevel, GameConfig gameConfig, GameState gameState, - String initialColor, boolean playAsOpponent, String bestPrevMove) { - - StateEvaluator stateEvaluator = new StateEvaluator(gameConfig); - List randomMoveCandidates = new ArrayList(); - - String colorPlaying = getColorToPlay(initialColor, playAsOpponent); - - List randomMoves = randomMoveGenerator.genMoves(gameConfig, - gameState, colorPlaying, DEFAULT_PLAYS_PER_LEVEL); - - for (String randomMove : randomMoves) { - GameState stateCopy = new GameState(gameState); - stateCopy.playStone(colorPlaying, randomMove); - if (recursionLevels > 1) { - randomMoveCandidates.add(findBestMonteCarloResult(recursionLevels - 1, - playsPerLevel, gameConfig, stateCopy, initialColor, - !playAsOpponent, randomMove)); - } else { - GameScore score = stateEvaluator.scoreGame(stateCopy); - randomMoveCandidates.add(new MoveCandidate(randomMove, score)); - } - } - - // TODO use a sorted list and just return the last element - MoveCandidate bestMove = randomMoveCandidates.get(0); - double bestScoreSoFar = bestMove.score.getScore(colorPlaying); - - for (MoveCandidate moveCandidate : randomMoveCandidates) { - if (moveCandidate.score.getScore(colorPlaying) > bestScoreSoFar) { - bestMove = moveCandidate; - bestScoreSoFar = moveCandidate.score.getScore(colorPlaying); - } - } - - // Fix to prevent thinking that the _opponent's_ best move is the move - // to make. - // If evaluating an opponent's move, the best move (for my opponent) is - // my previous move which gives the opponent the highest score. - if (playAsOpponent) { - return new MoveCandidate(bestPrevMove, bestMove.score); - } else { // if evaluating my own move, the move which gives me the - // highest score is the best. - return bestMove; - } - } - - private String getColorToPlay(String color, boolean playAsOpponent) { - if (playAsOpponent) { - if ("w".equals(color)) { - return "b"; - } else if ("b".equals(color)) { - return "w"; - } else { - return "?"; // invalid color will cause randomMoveGenerator to - // PASS - } - } else { - return color; - } - } - - /** - * MonteCarloMoveGenerator does not support this method - just pass. - * - * @param gameConfig - * @param gameState - * @param color - * @return - */ - @Override - public List genMoves(GameConfig gameConfig, GameState gameState, - String color, int nMoves) { - String[] pass = new String[] {PASS}; - return Arrays.asList(pass); - } -} \ No newline at end of file diff --git a/src/cs6601/p1/generator/MoveGenerator.java b/src/cs6601/p1/generator/MoveGenerator.java deleted file mode 100644 index 5bb7217..0000000 --- a/src/cs6601/p1/generator/MoveGenerator.java +++ /dev/null @@ -1,13 +0,0 @@ -package cs6601.p1.generator; - -import java.util.List; - -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; - -public interface MoveGenerator { - static final String PASS = "PASS"; - static final int ALL_MOVES = 0; - public String genMove(GameConfig gameConfig, GameState gameState, String color); - public List genMoves(GameConfig gameConfig, GameState gameState, String color, int nMoves); -} \ No newline at end of file diff --git a/src/cs6601/p1/Command.java b/src/net/woodyfolsom/msproj/Command.java similarity index 91% rename from src/cs6601/p1/Command.java rename to src/net/woodyfolsom/msproj/Command.java index 363ba23..26440d4 100644 --- a/src/cs6601/p1/Command.java +++ b/src/net/woodyfolsom/msproj/Command.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class Command { public enum TYPE { boardsize, clear_board, final_status_list, genmove, INVALID, komi, list_commands, name, play, quit, version }; diff --git a/src/cs6601/p1/CommandParser.java b/src/net/woodyfolsom/msproj/CommandParser.java similarity index 95% rename from src/cs6601/p1/CommandParser.java rename to src/net/woodyfolsom/msproj/CommandParser.java index 512c1a1..0dab934 100644 --- a/src/cs6601/p1/CommandParser.java +++ b/src/net/woodyfolsom/msproj/CommandParser.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import org.apache.log4j.Logger; diff --git a/src/cs6601/p1/GameBoard.java b/src/net/woodyfolsom/msproj/GameBoard.java similarity index 95% rename from src/cs6601/p1/GameBoard.java rename to src/net/woodyfolsom/msproj/GameBoard.java index d0fa790..28fa399 100644 --- a/src/cs6601/p1/GameBoard.java +++ b/src/net/woodyfolsom/msproj/GameBoard.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import java.util.Arrays; diff --git a/src/cs6601/p1/GameConfig.java b/src/net/woodyfolsom/msproj/GameConfig.java similarity index 86% rename from src/cs6601/p1/GameConfig.java rename to src/net/woodyfolsom/msproj/GameConfig.java index d8b3cbf..7fa78e5 100644 --- a/src/cs6601/p1/GameConfig.java +++ b/src/net/woodyfolsom/msproj/GameConfig.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class GameConfig { private double komi; diff --git a/src/net/woodyfolsom/msproj/GameController.java b/src/net/woodyfolsom/msproj/GameController.java new file mode 100644 index 0000000..afdac7e --- /dev/null +++ b/src/net/woodyfolsom/msproj/GameController.java @@ -0,0 +1,5 @@ +package net.woodyfolsom.msproj; + +public class GameController { + +} \ No newline at end of file diff --git a/src/cs6601/p1/GameScore.java b/src/net/woodyfolsom/msproj/GameScore.java similarity index 94% rename from src/cs6601/p1/GameScore.java rename to src/net/woodyfolsom/msproj/GameScore.java index ac31680..eda0e01 100644 --- a/src/cs6601/p1/GameScore.java +++ b/src/net/woodyfolsom/msproj/GameScore.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class GameScore { diff --git a/src/cs6601/p1/GameState.java b/src/net/woodyfolsom/msproj/GameState.java similarity index 95% rename from src/cs6601/p1/GameState.java rename to src/net/woodyfolsom/msproj/GameState.java index ce22a79..55c1cf6 100644 --- a/src/cs6601/p1/GameState.java +++ b/src/net/woodyfolsom/msproj/GameState.java @@ -1,11 +1,12 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import java.util.ArrayList; import java.util.List; +import net.woodyfolsom.msproj.policy.Policy; + import org.apache.log4j.Logger; -import cs6601.p1.generator.MoveGenerator; public class GameState { private static final Logger LOGGER = Logger.getLogger(GameState.class.getName()); @@ -61,7 +62,7 @@ public class GameState { public boolean playStone(String player, String coord) { //Opponent passes? Just ignore it. - if (MoveGenerator.PASS.equalsIgnoreCase(coord)) { + if (Policy.PASS.equalsIgnoreCase(coord)) { return true; } diff --git a/src/cs6601/p1/GoGame.java b/src/net/woodyfolsom/msproj/GoGame.java similarity index 73% rename from src/cs6601/p1/GoGame.java rename to src/net/woodyfolsom/msproj/GoGame.java index 911f2de..ffa836e 100644 --- a/src/cs6601/p1/GoGame.java +++ b/src/net/woodyfolsom/msproj/GoGame.java @@ -1,17 +1,18 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import java.io.IOException; import java.nio.charset.Charset; +import net.woodyfolsom.msproj.Command.TYPE; +import net.woodyfolsom.msproj.policy.AlphaBeta; +import net.woodyfolsom.msproj.policy.Minimax; +import net.woodyfolsom.msproj.policy.Policy; +import net.woodyfolsom.msproj.policy.MonteCarloUCT; +import net.woodyfolsom.msproj.policy.RandomMovePolicy; + import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; -import cs6601.p1.Command.TYPE; -import cs6601.p1.generator.AlphaBetaMoveGenerator; -import cs6601.p1.generator.MinimaxMoveGenerator; -import cs6601.p1.generator.MonteCarloMoveGenerator; -import cs6601.p1.generator.MoveGenerator; -import cs6601.p1.generator.RandomMoveGenerator; public class GoGame { private static final int INVALID_MOVE_GENERATOR = 1; @@ -21,34 +22,34 @@ public class GoGame { private boolean shutDown = false; private GameConfig gameConfig = new GameConfig(); private GameState gameState = new GameState(9); - private MoveGenerator moveGenerator; + private Policy moveGenerator; - public GoGame(MoveGenerator moveGenerator) { + public GoGame(Policy moveGenerator) { this.moveGenerator = moveGenerator; } public static void main(String[] args) { configureLogging(); if (args.length == 0) { - MoveGenerator defaultMoveGenerator = new MonteCarloMoveGenerator(); + Policy defaultMoveGenerator = new MonteCarloUCT(new RandomMovePolicy(), 2000L); LOGGER.info("No MoveGenerator specified. Using default: " + defaultMoveGenerator.getClass().getName()); new GoGame(defaultMoveGenerator).play(); } else { - new GoGame(createMoveGenerator(args[0])).play(); + new GoGame(createPolicy(args[0])).play(); } } - private static MoveGenerator createMoveGenerator(String generatorName) { - if ("random".equals(generatorName)) { - return new RandomMoveGenerator(); - } else if ("minimax".equals(generatorName)) { - return new MinimaxMoveGenerator(); - } else if ("alphabeta".equals(generatorName)) { - return new AlphaBetaMoveGenerator(); - } else if ("montecarlo".equals(generatorName)) { - return new MonteCarloMoveGenerator(); + private static Policy createPolicy(String policyName) { + if ("random".equals(policyName)) { + return new RandomMovePolicy(); + } else if ("minimax".equals(policyName)) { + return new Minimax(); + } else if ("alphabeta".equals(policyName)) { + return new AlphaBeta(); + } else if ("montecarlo".equals(policyName)) { + return new MonteCarloUCT(new RandomMovePolicy(), 2000L); } else { - LOGGER.info("Unable to create MoveGenerator for unsupported name: " + generatorName); + LOGGER.info("Unable to create Policy for unsupported name: " + policyName); System.exit(INVALID_MOVE_GENERATOR); //This line will never be executed but prevents the compiler from complaining. return null; @@ -77,7 +78,7 @@ public class GoGame { LOGGER.info("Generating move for:\n" + gameState); String player = cmd.getStringField(1); - String nextMove = moveGenerator.genMove(gameConfig, gameState, + String nextMove = moveGenerator.getAction(gameConfig, gameState, player); gameState.playStone(player, nextMove); diff --git a/src/cs6601/p1/GtpClient.java b/src/net/woodyfolsom/msproj/GtpClient.java similarity index 94% rename from src/cs6601/p1/GtpClient.java rename to src/net/woodyfolsom/msproj/GtpClient.java index 176d863..19a06c5 100644 --- a/src/cs6601/p1/GtpClient.java +++ b/src/net/woodyfolsom/msproj/GtpClient.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class GtpClient { diff --git a/src/cs6601/p1/LibertyCounter.java b/src/net/woodyfolsom/msproj/LibertyCounter.java similarity index 95% rename from src/cs6601/p1/LibertyCounter.java rename to src/net/woodyfolsom/msproj/LibertyCounter.java index 8935842..58fe9ec 100644 --- a/src/cs6601/p1/LibertyCounter.java +++ b/src/net/woodyfolsom/msproj/LibertyCounter.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class LibertyCounter { public static int countLiberties(GameBoard gameBoard, char colLabel, int rowNum, char groupColor) { diff --git a/src/cs6601/p1/StateEvaluator.java b/src/net/woodyfolsom/msproj/StateEvaluator.java similarity index 92% rename from src/cs6601/p1/StateEvaluator.java rename to src/net/woodyfolsom/msproj/StateEvaluator.java index 2090bd6..2d7e83c 100644 --- a/src/cs6601/p1/StateEvaluator.java +++ b/src/net/woodyfolsom/msproj/StateEvaluator.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class StateEvaluator { private final GameConfig gameConfig; diff --git a/src/cs6601/p1/TerritoryMarker.java b/src/net/woodyfolsom/msproj/TerritoryMarker.java similarity index 95% rename from src/cs6601/p1/TerritoryMarker.java rename to src/net/woodyfolsom/msproj/TerritoryMarker.java index 2f7436e..b6787c4 100644 --- a/src/cs6601/p1/TerritoryMarker.java +++ b/src/net/woodyfolsom/msproj/TerritoryMarker.java @@ -1,4 +1,4 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; public class TerritoryMarker { public static final char BLACK_TERRITORY = 'x'; diff --git a/src/net/woodyfolsom/msproj/ZobristHashGenerator.java b/src/net/woodyfolsom/msproj/ZobristHashGenerator.java new file mode 100644 index 0000000..6868093 --- /dev/null +++ b/src/net/woodyfolsom/msproj/ZobristHashGenerator.java @@ -0,0 +1,27 @@ +package net.woodyfolsom.msproj; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class ZobristHashGenerator { + private long[] randomBitFields; + + private ZobristHashGenerator() { + } + + public static ZobristHashGenerator getInstance(int boardSize) { + int nRandomFields = 3 * boardSize * boardSize; + ZobristHashGenerator zobHashGen = new ZobristHashGenerator(); + SecureRandom secureRandom = new SecureRandom(); + zobHashGen.randomBitFields = new long[nRandomFields]; + byte[] nextBytes = new byte[8]; + for (int i = 0; i < nRandomFields; i++) { + secureRandom.nextBytes(nextBytes); + zobHashGen.randomBitFields[i] = new BigInteger(nextBytes) + .longValue(); + } + // TODO add check for minimum hamming distance/colinearity check + return zobHashGen; + } + +} diff --git a/src/net/woodyfolsom/msproj/policy/ActionGenerator.java b/src/net/woodyfolsom/msproj/policy/ActionGenerator.java new file mode 100644 index 0000000..ed0166a --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/ActionGenerator.java @@ -0,0 +1,13 @@ +package net.woodyfolsom.msproj.policy; + +import java.util.List; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; + +public interface ActionGenerator { + public static final int ALL_ACTIONS = 0; + + public List getActions(GameConfig gameConfig, GameState gameState, + String color, int numActions); +} diff --git a/src/net/woodyfolsom/msproj/policy/AlphaBeta.java b/src/net/woodyfolsom/msproj/policy/AlphaBeta.java new file mode 100644 index 0000000..be966a6 --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/AlphaBeta.java @@ -0,0 +1,144 @@ +package net.woodyfolsom.msproj.policy; + +import java.util.List; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.StateEvaluator; + +//import org.apache.log4j.Logger; + +public class AlphaBeta implements Policy { + //private static final Logger LOGGER = Logger.getLogger(AlphaBeta.class + // .getName()); + private static final int DEFAULT_RECURSIVE_PLAYS = 3; + private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); + + private String bestPick = Policy.PASS; + + @Override + public String getAction(GameConfig gameConfig, GameState gameState, + String initialColor) { + + int alpha = Integer.MIN_VALUE; + int beta = Integer.MAX_VALUE; + + if ("b".equals(initialColor)) { + getMaxValue(gameConfig, gameState, initialColor, false, + DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta); + return bestPick; + } else if ("w".equals(initialColor)) { + getMinValue(gameConfig, gameState, initialColor, false, + DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta); + return bestPick; + } else { + return Policy.PASS; + } + } + + private int getMaxValue(GameConfig gameConfig, GameState gameState, + String initialColor, boolean playAsOpponent, int recursionLevel, + int alpha, int beta) { + if (terminalTest(recursionLevel)) { + return getUtility(gameConfig, gameState); + } + + String colorPlaying = getColorToPlay(initialColor, playAsOpponent); + + List validMoves = validMoveGenerator.getActions(gameConfig, + gameState, colorPlaying, ActionGenerator.ALL_ACTIONS); + + int value = Integer.MIN_VALUE; + + for (String nextMove : validMoves) { + GameState nextState = new GameState(gameState); + + if (!nextState.playStone(colorPlaying, nextMove)) { + throw new RuntimeException( + "Illegal move attempted during search!"); + } + + int minValue = getMinValue(gameConfig, nextState, initialColor, + !playAsOpponent, recursionLevel - 1, alpha, beta); + + if (minValue > value) { + value = minValue; + if (recursionLevel == DEFAULT_RECURSIVE_PLAYS * 2) { + bestPick = nextMove; + } + } + + if (value >= beta) { + return value; + } + alpha = Math.max(alpha, value); + } + + return value; + } + + private int getMinValue(GameConfig gameConfig, GameState gameState, + String initialColor, boolean playAsOpponent, int recursionLevel, + int alpha, int beta) { + if (terminalTest(recursionLevel)) { + return getUtility(gameConfig, gameState); + } + + String colorPlaying = getColorToPlay(initialColor, playAsOpponent); + + List validMoves = validMoveGenerator.getActions(gameConfig, + gameState, colorPlaying, ActionGenerator.ALL_ACTIONS); + + int value = Integer.MAX_VALUE; + + for (String nextMove : validMoves) { + GameState nextState = new GameState(gameState); + + if (!nextState.playStone(colorPlaying, nextMove)) { + throw new RuntimeException( + "Illegal move attempted during search!"); + } + + int maxValue = getMaxValue(gameConfig, nextState, initialColor, + !playAsOpponent, recursionLevel - 1, alpha, beta); + + if (maxValue < value) { + value = maxValue; + if (recursionLevel == 2 * DEFAULT_RECURSIVE_PLAYS) { + bestPick = nextMove; + } + } + + if (value <= alpha) { + return value; + } + beta = Math.min(beta, value); + } + + return value; + } + + private boolean terminalTest(int recursionLevel) { + return recursionLevel < 1; + } + + private int getUtility(GameConfig gameConfig, GameState gameState) { + StateEvaluator stateEvaluator = new StateEvaluator(gameConfig); + return stateEvaluator.scoreGame(gameState).getAggregateScore(); + } + + private String getColorToPlay(String color, boolean playAsOpponent) { + if (playAsOpponent) { + if ("w".equals(color)) { + return "b"; + } else if ("b".equals(color)) { + return "w"; + } else { + return "?"; // invalid color will cause randomMoveGenerator to + // PASS + } + } else { + return color; + } + } +} \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/policy/GameTreeNode.java b/src/net/woodyfolsom/msproj/policy/GameTreeNode.java new file mode 100644 index 0000000..2ef927f --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/GameTreeNode.java @@ -0,0 +1,60 @@ +package net.woodyfolsom.msproj.policy; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; + +public abstract class GameTreeNode { + private GameConfig gameConfig; + private GameState gameState; + private GameTreeNode parent; + private Map children = new HashMap(); + private String player; + + public GameTreeNode(GameConfig gameConfig, GameState gameState, + String player) { + this.gameConfig = gameConfig; + this.gameState = gameState; + this.player = player; + } + + public void addChild(String action, GameTreeNode child) { + children.put(action, child); + child.parent = this; + } + + public Set getActions() { + return children.keySet(); + } + + public GameTreeNode getChild(String action) { + return children.get(action); + } + + public int getChildrenSize() { + return children.size(); + } + + public GameConfig getGameConfig() { + return gameConfig; + } + + public GameState getGameState() { + return gameState; + } + + public GameTreeNode getParent() { + return parent; + } + + public String getPlayer() { + return player; + } + + public boolean isRoot() { + return parent == null; + } +} \ No newline at end of file diff --git a/src/cs6601/p1/generator/MinimaxMoveGenerator.java b/src/net/woodyfolsom/msproj/policy/Minimax.java similarity index 68% rename from src/cs6601/p1/generator/MinimaxMoveGenerator.java rename to src/net/woodyfolsom/msproj/policy/Minimax.java index 1173171..f11174c 100644 --- a/src/cs6601/p1/generator/MinimaxMoveGenerator.java +++ b/src/net/woodyfolsom/msproj/policy/Minimax.java @@ -1,32 +1,30 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import java.util.ArrayList; -import java.util.Arrays; +//import java.util.Arrays; import java.util.List; -import org.apache.log4j.Logger; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameScore; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.StateEvaluator; -import cs6601.p1.GameConfig; -import cs6601.p1.GameScore; -import cs6601.p1.GameState; -import cs6601.p1.StateEvaluator; +//import org.apache.log4j.Logger; -public class MinimaxMoveGenerator implements MoveGenerator { - private static final Logger LOGGER = Logger.getLogger(MinimaxMoveGenerator.class.getName()); - - //private static final Logger LOGGER = Logger - // .getLogger(MonteCarloMoveGenerator.class.getName()); + +public class Minimax implements Policy { + //private static final Logger LOGGER = Logger.getLogger(Minimax.class.getName()); private static final int DEFAULT_RECURSIVE_PLAYS = 1; private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); @Override - public String genMove(GameConfig gameConfig, GameState gameState, + public String getAction(GameConfig gameConfig, GameState gameState, String color) { MoveCandidate moveCandidate = findBestMinimaxResult( DEFAULT_RECURSIVE_PLAYS * 2, - gameConfig, gameState, color, false, PASS); + gameConfig, gameState, color, false, Policy.PASS); return moveCandidate.move; } @@ -40,8 +38,8 @@ public class MinimaxMoveGenerator implements MoveGenerator { String colorPlaying = getColorToPlay(initialColor, playAsOpponent); - List validMoves = validMoveGenerator.genMoves(gameConfig, - gameState, colorPlaying, MoveGenerator.ALL_MOVES); + List validMoves = validMoveGenerator.getActions(gameConfig, + gameState, colorPlaying, ActionGenerator.ALL_ACTIONS); for (String randomMove : validMoves) { GameState stateCopy = new GameState(gameState); @@ -71,6 +69,7 @@ public class MinimaxMoveGenerator implements MoveGenerator { // to make. // If evaluating an opponent's move, the best move (for my opponent) is // my previous move which gives the opponent the highest score. + // This should only happen if recursionLevels is initially odd. if (playAsOpponent) { return new MoveCandidate(bestPrevMove, bestMove.score); } else { // if evaluating my own move, the move which gives me the @@ -93,15 +92,4 @@ public class MinimaxMoveGenerator implements MoveGenerator { return color; } } - - /** - * MinimaxMoveGenerator does not support this method. - */ - @Override - public List genMoves(GameConfig gameConfig, GameState gameState, - String color, int nMoves) { - String[] pass = new String[] {PASS}; - LOGGER.info("Minimax genMoves() stub returning [PASS]"); - return Arrays.asList(pass); - } } \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/policy/MonteCarlo.java b/src/net/woodyfolsom/msproj/policy/MonteCarlo.java new file mode 100644 index 0000000..aacef92 --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/MonteCarlo.java @@ -0,0 +1,61 @@ +package net.woodyfolsom.msproj.policy; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; + +public abstract class MonteCarlo implements Policy { + protected Policy movePolicy; + protected long searchTimeLimit; + + public MonteCarlo(Policy movePolicy, long searchTimeLimit) { + this.movePolicy = movePolicy; + this.searchTimeLimit = searchTimeLimit; + } + + public abstract MonteCarloTreeNode descend(MonteCarloTreeNode node); + + @Override + public String getAction(GameConfig gameConfig, GameState gameState, + String initialColor) { + long initialTime = System.currentTimeMillis(); + + //If for some reason no moves are evaluated within the time limit, pass. + //Note that this may lose the game by forfeit even when picking any random move could + //result in a win. + + String bestMove = Policy.PASS; + + MonteCarloTreeNode rootNode = new MonteCarloTreeNode(gameConfig, gameState, initialColor); + MonteCarloTreeNode selectedNode; + while (System.currentTimeMillis() - initialTime < searchTimeLimit) { + //TODO these return types may need to be lists for some MC methods + selectedNode = descend(rootNode); + selectedNode = grow(selectedNode); + int reward = rollout(selectedNode); + update(selectedNode, reward); + } + + return bestMove; + } + + public abstract MonteCarloTreeNode grow(MonteCarloTreeNode node); + + public abstract int rollout(MonteCarloTreeNode node); + + public abstract void update(MonteCarloTreeNode node, int reward); + + static String getColorToPlay(String color, boolean playAsOpponent) { + if (playAsOpponent) { + if ("w".equals(color)) { + return "b"; + } else if ("b".equals(color)) { + return "w"; + } else { + return "?"; // invalid color will cause randomMoveGenerator to + // PASS + } + } else { + return color; + } + } +} \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java b/src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java new file mode 100644 index 0000000..e9bff00 --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java @@ -0,0 +1,30 @@ +package net.woodyfolsom.msproj.policy; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; + +public class MonteCarloTreeNode extends GameTreeNode { + private int numVisits; + private int numWins; + + public MonteCarloTreeNode(GameConfig gameConfig, GameState gameState, + String player) { + super(gameConfig, gameState, player); + } + + public int getNumVisits() { + return numVisits; + } + + public void setNumVisits(int numVisits) { + this.numVisits = numVisits; + } + + public int getNumWins() { + return numWins; + } + + public void setNumWins(int numWins) { + this.numWins = numWins; + } +} diff --git a/src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java b/src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java new file mode 100644 index 0000000..829ec47 --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java @@ -0,0 +1,34 @@ +package net.woodyfolsom.msproj.policy; + + +public class MonteCarloUCT extends MonteCarlo { + + public MonteCarloUCT(Policy movePolicy, long searchTimeLimit) { + super(movePolicy, searchTimeLimit); + } + + @Override + public MonteCarloTreeNode descend(MonteCarloTreeNode node) { + // TODO Auto-generated method stub + return null; + } + + @Override + public MonteCarloTreeNode grow(MonteCarloTreeNode node) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int rollout(MonteCarloTreeNode node) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void update(MonteCarloTreeNode node, int reward) { + // TODO Auto-generated method stub + + } + +} \ No newline at end of file diff --git a/src/cs6601/p1/generator/MoveCandidate.java b/src/net/woodyfolsom/msproj/policy/MoveCandidate.java similarity index 67% rename from src/cs6601/p1/generator/MoveCandidate.java rename to src/net/woodyfolsom/msproj/policy/MoveCandidate.java index cc91fd5..c49b9f1 100644 --- a/src/cs6601/p1/generator/MoveCandidate.java +++ b/src/net/woodyfolsom/msproj/policy/MoveCandidate.java @@ -1,6 +1,6 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; -import cs6601.p1.GameScore; +import net.woodyfolsom.msproj.GameScore; public class MoveCandidate { public final String move; diff --git a/src/net/woodyfolsom/msproj/policy/Policy.java b/src/net/woodyfolsom/msproj/policy/Policy.java new file mode 100644 index 0000000..79d66fd --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/Policy.java @@ -0,0 +1,10 @@ +package net.woodyfolsom.msproj.policy; + +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; + + +public interface Policy { + static final String PASS = "PASS"; + public String getAction(GameConfig gameConfig, GameState gameState, String color); +} \ No newline at end of file diff --git a/src/cs6601/p1/generator/RandomMoveGenerator.java b/src/net/woodyfolsom/msproj/policy/RandomMovePolicy.java similarity index 83% rename from src/cs6601/p1/generator/RandomMoveGenerator.java rename to src/net/woodyfolsom/msproj/policy/RandomMovePolicy.java index bb1b3dc..5f2668c 100644 --- a/src/cs6601/p1/generator/RandomMoveGenerator.java +++ b/src/net/woodyfolsom/msproj/policy/RandomMovePolicy.java @@ -1,17 +1,18 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import java.util.ArrayList; import java.util.List; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; -public class RandomMoveGenerator implements MoveGenerator { + +public class RandomMovePolicy implements Policy { /** * Does NOT modify the gameState. */ - public String genMove(GameConfig gameConfig, GameState gameState, + public String getAction(GameConfig gameConfig, GameState gameState, String color) { GameState gameStateCopy = new GameState(gameState); List emptyCoordinates = gameStateCopy.getEmptyCoords(); diff --git a/src/cs6601/p1/generator/ValidMoveGenerator.java b/src/net/woodyfolsom/msproj/policy/ValidMoveGenerator.java similarity index 52% rename from src/cs6601/p1/generator/ValidMoveGenerator.java rename to src/net/woodyfolsom/msproj/policy/ValidMoveGenerator.java index 713fa67..f174a78 100644 --- a/src/cs6601/p1/generator/ValidMoveGenerator.java +++ b/src/net/woodyfolsom/msproj/policy/ValidMoveGenerator.java @@ -1,26 +1,18 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import org.apache.log4j.Logger; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; +//import org.apache.log4j.Logger; -public class ValidMoveGenerator implements MoveGenerator { - private static final Logger LOGGER = Logger.getLogger(MinimaxMoveGenerator.class.getName()); - - @Override - public String genMove(GameConfig gameConfig, GameState gameState, - String color) { - LOGGER.info("ValidMoveGenerator genMove() stub returning PASS"); - return PASS; - } +public class ValidMoveGenerator implements ActionGenerator { + //private static final Logger LOGGER = Logger.getLogger(ValidMoveGenerator.class.getName()); @Override - public List genMoves(GameConfig gameConfig, GameState gameState, + public List getActions(GameConfig gameConfig, GameState gameState, String color, int nMoves) { GameState gameStateCopy = new GameState(gameState); @@ -36,7 +28,7 @@ public class ValidMoveGenerator implements MoveGenerator { } if (validMoves.size() == 0) { - validMoves.add(PASS); + validMoves.add(Policy.PASS); } return validMoves; diff --git a/test/cs6601/p1/CaptureTest.java b/test/net/woodyfolsom/msproj/CaptureTest.java similarity index 88% rename from test/cs6601/p1/CaptureTest.java rename to test/net/woodyfolsom/msproj/CaptureTest.java index 19434de..e6fa493 100644 --- a/test/cs6601/p1/CaptureTest.java +++ b/test/net/woodyfolsom/msproj/CaptureTest.java @@ -1,9 +1,15 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameScore; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.StateEvaluator; + import org.junit.Test; public class CaptureTest { diff --git a/test/cs6601/p1/GameScoreTest.java b/test/net/woodyfolsom/msproj/GameScoreTest.java similarity index 85% rename from test/cs6601/p1/GameScoreTest.java rename to test/net/woodyfolsom/msproj/GameScoreTest.java index 82a437c..2c127c9 100644 --- a/test/cs6601/p1/GameScoreTest.java +++ b/test/net/woodyfolsom/msproj/GameScoreTest.java @@ -1,7 +1,9 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import static org.junit.Assert.assertEquals; +import net.woodyfolsom.msproj.GameScore; + import org.junit.Test; public class GameScoreTest { diff --git a/test/cs6601/p1/IllegalMoveTest.java b/test/net/woodyfolsom/msproj/IllegalMoveTest.java similarity index 92% rename from test/cs6601/p1/IllegalMoveTest.java rename to test/net/woodyfolsom/msproj/IllegalMoveTest.java index a665017..e102dc3 100644 --- a/test/cs6601/p1/IllegalMoveTest.java +++ b/test/net/woodyfolsom/msproj/IllegalMoveTest.java @@ -1,8 +1,11 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameState; + import org.junit.Test; public class IllegalMoveTest { diff --git a/test/cs6601/p1/LegalMoveTest.java b/test/net/woodyfolsom/msproj/LegalMoveTest.java similarity index 77% rename from test/cs6601/p1/LegalMoveTest.java rename to test/net/woodyfolsom/msproj/LegalMoveTest.java index da4f05f..6f0e499 100644 --- a/test/cs6601/p1/LegalMoveTest.java +++ b/test/net/woodyfolsom/msproj/LegalMoveTest.java @@ -1,7 +1,10 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import static org.junit.Assert.assertTrue; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameState; + import org.junit.Test; public class LegalMoveTest { diff --git a/test/cs6601/p1/StateEvaluatorTest.java b/test/net/woodyfolsom/msproj/StateEvaluatorTest.java similarity index 89% rename from test/cs6601/p1/StateEvaluatorTest.java rename to test/net/woodyfolsom/msproj/StateEvaluatorTest.java index 90a1c00..0767f99 100644 --- a/test/cs6601/p1/StateEvaluatorTest.java +++ b/test/net/woodyfolsom/msproj/StateEvaluatorTest.java @@ -1,12 +1,16 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameScore; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.StateEvaluator; + import org.junit.Test; -import cs6601.p1.generator.AlphaBetaMoveGenerator; -import cs6601.p1.generator.MoveGenerator; public class StateEvaluatorTest { GameConfig gameConfig = new GameConfig(); diff --git a/test/cs6601/p1/TerritoryFinderTest.java b/test/net/woodyfolsom/msproj/TerritoryFinderTest.java similarity index 73% rename from test/cs6601/p1/TerritoryFinderTest.java rename to test/net/woodyfolsom/msproj/TerritoryFinderTest.java index b7c971e..1e27b67 100644 --- a/test/cs6601/p1/TerritoryFinderTest.java +++ b/test/net/woodyfolsom/msproj/TerritoryFinderTest.java @@ -1,4 +1,8 @@ -package cs6601.p1; +package net.woodyfolsom.msproj; + +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.TerritoryMarker; import org.junit.Test; diff --git a/test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java b/test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java new file mode 100644 index 0000000..68f72bf --- /dev/null +++ b/test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java @@ -0,0 +1,17 @@ +package net.woodyfolsom.msproj; + +import static org.junit.Assert.*; + +import net.woodyfolsom.msproj.ZobristHashGenerator; + +import org.junit.Test; + +public class ZobristHashGeneratorTest { + + @Test + public void testConstructor5x5() { + ZobristHashGenerator zobHashGen = ZobristHashGenerator.getInstance(5); + assertNotNull(zobHashGen); + } + +} diff --git a/test/cs6601/p1/generator/AlphaBetaTest.java b/test/net/woodyfolsom/msproj/policy/AlphaBetaTest.java similarity index 60% rename from test/cs6601/p1/generator/AlphaBetaTest.java rename to test/net/woodyfolsom/msproj/policy/AlphaBetaTest.java index e84547e..80df6cd 100644 --- a/test/cs6601/p1/generator/AlphaBetaTest.java +++ b/test/net/woodyfolsom/msproj/policy/AlphaBetaTest.java @@ -1,53 +1,57 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import static org.junit.Assert.assertEquals; -import org.junit.Test; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.policy.AlphaBeta; +import net.woodyfolsom.msproj.policy.Policy; -import cs6601.p1.GameBoard; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; +import org.junit.Test; public class AlphaBetaTest { @Test public void testGenmoveAsW() { - MoveGenerator moveGenerator = new AlphaBetaMoveGenerator(); + Policy treeSearch = new AlphaBeta(); GameState gameState = new GameState(6); gameState.playStone('A', 2, GameBoard.WHITE_STONE); gameState.playStone('B', 1, GameBoard.WHITE_STONE); gameState.playStone('C', 2, GameBoard.WHITE_STONE); gameState.playStone('B', 2, GameBoard.BLACK_STONE); - - String move = moveGenerator.genMove(new GameConfig(), gameState, "b"); + + String move = treeSearch.getAction(new GameConfig(), gameState, "b"); System.out.println(gameState); - + System.out.println("Generated move: " + move); assertEquals("Expected B3 but was: " + move, "B3", move); gameState.playStone("b", move); - + System.out.println(gameState); - - assertEquals(MoveGenerator.PASS,moveGenerator.genMove(new GameConfig(), gameState, "?")); + + assertEquals(Policy.PASS, + treeSearch.getAction(new GameConfig(), gameState, "?")); } - + @Test public void testGenmoveAsB() { - MoveGenerator moveGenerator = new AlphaBetaMoveGenerator(); + Policy treeSearch = new AlphaBeta(); GameState gameState = new GameState(6); gameState.playStone('A', 2, GameBoard.BLACK_STONE); gameState.playStone('B', 1, GameBoard.BLACK_STONE); gameState.playStone('C', 2, GameBoard.BLACK_STONE); gameState.playStone('B', 2, GameBoard.WHITE_STONE); - - String move = moveGenerator.genMove(new GameConfig(), gameState, "b"); + + String move = treeSearch.getAction(new GameConfig(), gameState, "b"); System.out.println(gameState); - + System.out.println("Generated move: " + move); assertEquals("Expected B3 but was: " + move, "B3", move); gameState.playStone("b", move); - + System.out.println(gameState); - - assertEquals(MoveGenerator.PASS,moveGenerator.genMove(new GameConfig(), gameState, "?")); + + assertEquals(Policy.PASS, + treeSearch.getAction(new GameConfig(), gameState, "?")); } } \ No newline at end of file diff --git a/test/cs6601/p1/generator/MinimaxTest.java b/test/net/woodyfolsom/msproj/policy/MinimaxTest.java similarity index 55% rename from test/cs6601/p1/generator/MinimaxTest.java rename to test/net/woodyfolsom/msproj/policy/MinimaxTest.java index 8f5f1e2..148a47e 100644 --- a/test/cs6601/p1/generator/MinimaxTest.java +++ b/test/net/woodyfolsom/msproj/policy/MinimaxTest.java @@ -1,32 +1,33 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import static org.junit.Assert.assertEquals; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.policy.Policy; + import org.junit.Test; -import cs6601.p1.GameBoard; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; -import cs6601.p1.generator.MoveGenerator; public class MinimaxTest { @Test public void testGenmove() { - MoveGenerator moveGenerator = new MinimaxMoveGenerator(); + Policy moveGenerator = new Minimax(); GameState gameState = new GameState(5); gameState.playStone('A', 2, GameBoard.BLACK_STONE); gameState.playStone('B', 1, GameBoard.BLACK_STONE); gameState.playStone('C', 2, GameBoard.BLACK_STONE); gameState.playStone('B', 4, GameBoard.BLACK_STONE); - String move = moveGenerator.genMove(new GameConfig(), gameState, "w"); + String move = moveGenerator.getAction(new GameConfig(), gameState, "w"); System.out.println("Generated move: " + move); gameState.playStone("w", move); System.out.println(gameState); - assertEquals(MoveGenerator.PASS,moveGenerator.genMove(new GameConfig(), gameState, "?")); + assertEquals(Policy.PASS,moveGenerator.getAction(new GameConfig(), gameState, "?")); System.out.println(gameState); } diff --git a/test/cs6601/p1/generator/RandomTest.java b/test/net/woodyfolsom/msproj/policy/RandomTest.java similarity index 66% rename from test/cs6601/p1/generator/RandomTest.java rename to test/net/woodyfolsom/msproj/policy/RandomTest.java index ed78e67..b6f9415 100644 --- a/test/cs6601/p1/generator/RandomTest.java +++ b/test/net/woodyfolsom/msproj/policy/RandomTest.java @@ -1,27 +1,28 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.policy.Policy; +import net.woodyfolsom.msproj.policy.RandomMovePolicy; + import org.junit.Test; -import cs6601.p1.GameBoard; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; -import cs6601.p1.generator.MoveGenerator; -import cs6601.p1.generator.RandomMoveGenerator; public class RandomTest { @Test public void testGenmove() { - MoveGenerator moveGenerator = new RandomMoveGenerator(); + Policy moveGenerator = new RandomMovePolicy(); GameState gameState = new GameState(5); - moveGenerator.genMove(new GameConfig(), gameState, "b"); + moveGenerator.getAction(new GameConfig(), gameState, "b"); gameState = new GameState(5); - moveGenerator.genMove(new GameConfig(), gameState, "w"); + moveGenerator.getAction(new GameConfig(), gameState, "w"); - assertEquals(MoveGenerator.PASS,moveGenerator.genMove(new GameConfig(), gameState, "?")); + assertEquals(Policy.PASS,moveGenerator.getAction(new GameConfig(), gameState, "?")); System.out.println(gameState); } @@ -46,7 +47,7 @@ public class RandomTest { assertTrue(gameState.playStone('D', 3, GameBoard.WHITE_STONE)); System.out.println(gameState); //This is correct - checked vs. MFOG - assertEquals("B3", new RandomMoveGenerator().genMove(new GameConfig(), gameState, "w")); + assertEquals("B3", new RandomMovePolicy().getAction(new GameConfig(), gameState, "w")); System.out.println(gameState); } } diff --git a/test/cs6601/p1/generator/ValidMoveGeneratorTest.java b/test/net/woodyfolsom/msproj/policy/ValidMoveGeneratorTest.java similarity index 71% rename from test/cs6601/p1/generator/ValidMoveGeneratorTest.java rename to test/net/woodyfolsom/msproj/policy/ValidMoveGeneratorTest.java index c84033c..9e240a7 100644 --- a/test/cs6601/p1/generator/ValidMoveGeneratorTest.java +++ b/test/net/woodyfolsom/msproj/policy/ValidMoveGeneratorTest.java @@ -1,14 +1,16 @@ -package cs6601.p1.generator; +package net.woodyfolsom.msproj.policy; import static org.junit.Assert.*; import java.util.List; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.policy.ValidMoveGenerator; + import org.junit.Test; -import cs6601.p1.GameBoard; -import cs6601.p1.GameConfig; -import cs6601.p1.GameState; public class ValidMoveGeneratorTest { @@ -30,7 +32,7 @@ public class ValidMoveGeneratorTest { gameState.playStone('C', 2, GameBoard.WHITE_STONE); assertFalse(gameState.playStone('A', 1, GameBoard.BLACK_STONE)); - List validMoves = new ValidMoveGenerator().genMoves(new GameConfig(), gameState, "b",0); + List validMoves = new ValidMoveGenerator().getActions(new GameConfig(), gameState, "b",0); assertTrue(validMoves.size() > 0); for (String vm : validMoves) { System.out.println(vm);