Refactoring in progress.

Player and Action classes are now singletons (factory pattern) rather than String values.
Implementing more general treesearch code for minimax, alpha-beta, monte carlo using simplified backup logic.
This commit is contained in:
cs6601
2012-08-30 08:41:03 -04:00
parent b44b666663
commit 2e40440838
26 changed files with 647 additions and 433 deletions

View File

@@ -0,0 +1,73 @@
package net.woodyfolsom.msproj;
import java.util.HashMap;
import java.util.Map;
public class Action {
private static final Map<String, Action> actionMap = new HashMap<String,Action>();
private char column = 'x';
private int row = 0;
//private Player player;
private String move;
public static final Action NONE = new Action("NONE", /*Player.NONE,*/ 'x', 0);
public static final Action PASS = new Action("PASS", /*Player.NONE,*/ 'x', 0);
private Action(String move, /*Player player,*/ char column, int row) {
this.move = move;
//this.player = player;
this.column = column;
this.row = row;
}
public static final Action getInstance(/*String playerName,*/ String move) {
if (move == null || "NONE".equals(move) || "PASS".equals(move)) {
throw new IllegalArgumentException("Illegal move: " + move);
}
if (actionMap.containsKey(move)) {
return actionMap.get(move);
}
/*
Player player;
if ("b".equals(playerName)) {
player = Player.BLACK;
} else if ("w".equals(playerName)) {
player = Player.WHITE;
} else {
return Action.NONE;
}*/
char col = move.charAt(0);
int row = Integer.valueOf(move.substring(1));
Action action = new Action(move, col, row);
actionMap.put(move, action);
return action;
}
public char getColumn() {
return column;
}
public int getRow() {
return row;
}
public boolean isNone() {
return this == Action.NONE;
}
public boolean isPass() {
return this == Action.PASS;
}
@Override
public String toString() {
return move;
}
}

View File

@@ -28,11 +28,11 @@ public class GameScore {
return NORMALIZED_ZERO_SCORE + 2 * blackScore - ((int)(2 * (whiteScore + komi)));
}
public double getScore(String color) {
if ("w".equals(color)) {
return getWhiteScore();
} else if ("b".equals(color)) {
public double getScore(Player color) {
if (color == Player.BLACK) {
return getBlackScore();
} else if (color == Player.WHITE) {
return getWhiteScore();
} else {
return 0.0;
}
@@ -42,6 +42,14 @@ public class GameScore {
return (double)whiteScore + komi;
}
public boolean isWinner(String color) {
if ("w".equals(color)) {
return getWhiteScore() < NORMALIZED_ZERO_SCORE;
} else {
return getBlackScore() > NORMALIZED_ZERO_SCORE;
}
}
public String toString() {
return "B: " + blackScore + "W: "+ whiteScore+"K:" + komi;
}

View File

@@ -3,8 +3,6 @@ package net.woodyfolsom.msproj;
import java.util.ArrayList;
import java.util.List;
import net.woodyfolsom.msproj.policy.Policy;
import org.apache.log4j.Logger;
@@ -60,28 +58,19 @@ public class GameState {
return whitePrisoners;
}
public boolean playStone(String player, String coord) {
public boolean playStone(Player player, String move) {
//Opponent passes? Just ignore it.
if (Policy.PASS.equalsIgnoreCase(coord)) {
Action action = Action.getInstance(move);
if (action.isPass()) {
return true;
}
//LOGGER.info("Playing " + player + " at " + coord);
char stoneColor;
if ("b".equals(player)) {
stoneColor = GameBoard.BLACK_STONE;
} else if ("w".equals(player)) {
stoneColor = GameBoard.WHITE_STONE;
} else {
if (action.isNone()) {
return false;
}
char col = coord.charAt(0);
int row = Integer.valueOf(coord.substring(1));
//LOGGER.info("Playing " + stoneColor + " at " + col + row);
return playStone(col,row, stoneColor);
return playStone(player, action);
}
/**
* Places a stone at the requested coordinate. Placement is legal if the
@@ -97,20 +86,22 @@ public class GameState {
* @param stone
* @return
*/
public boolean playStone(char colLabel, int rowNum, char stoneSymbol) {
char currentStone = gameBoard.getSymbolAt(colLabel, rowNum);
public boolean playStone(Player player, Action action) {
char currentStone = gameBoard.getSymbolAt(action.getColumn(), action.getRow());
if (currentStone != GameBoard.EMPTY_INTERSECTION) {
return false;
}
//Place stone as requested, then check for (1) captured neighbors and (2) illegal move due to 0 liberties.
gameBoard.setSymbolAt(colLabel, rowNum, stoneSymbol);
char stoneSymbol = player.getStoneSymbol();
gameBoard.setSymbolAt(action.getColumn(), action.getRow(), stoneSymbol);
//look for captured adjacent groups and increment the prisoner counter
char opponentSymbol = GameBoard.getOpponentSymbol(stoneSymbol);
char opponentSymbol = GameBoard.getOpponentSymbol(player.getStoneSymbol());
int col = GameBoard.getColumnIndex(colLabel);
int row = rowNum - 1;
int col = GameBoard.getColumnIndex(action.getColumn());
int row = action.getRow() - 1;
int prisonerCount = 0;
if (col > 0 && gameBoard.getSymbolAt(col-1, row) == opponentSymbol) {
@@ -153,8 +144,8 @@ public class GameState {
}
//Moved test for 0 liberties until after attempting to capture neighboring groups.
if (0 == LibertyCounter.countLiberties(gameBoard, colLabel, rowNum, stoneSymbol)) {
gameBoard.removeStone(colLabel,rowNum);
if (0 == LibertyCounter.countLiberties(gameBoard, action.getColumn(), action.getRow(), stoneSymbol)) {
gameBoard.removeStone(action.getColumn(),action.getRow());
return false;
}
return true;

View File

@@ -77,14 +77,24 @@ public class GoGame {
case genmove:
LOGGER.info("Generating move for:\n" + gameState);
String player = cmd.getStringField(1);
String nextMove = moveGenerator.getAction(gameConfig, gameState,
String playerName = cmd.getStringField(1);
Player player;
if ("b".equals(playerName)) {
player = Player.BLACK;
} else if ("w".equals(playerName)) {
player = Player.WHITE;
} else {
throw new RuntimeException("Invalid player name - cannot generator move for:" + cmd);
}
Action nextMove = moveGenerator.getAction(gameConfig, gameState,
player);
gameState.playStone(player, nextMove);
LOGGER.info(new StateEvaluator(gameConfig).scoreGame(gameState));
System.out.println("="
+ nextMove.toLowerCase() + "\n");
+ nextMove.toString() + "\n");
break;
case komi:
@@ -109,7 +119,7 @@ public class GoGame {
shutDown = true;
break;
case play:
if (gameState.playStone(cmd.getStringField(1), cmd
if (gameState.playStone(Player.getInstance(cmd.getStringField(1)), cmd
.getStringField(2).toUpperCase())) {
System.out.println("=\n");
} else {
@@ -147,4 +157,18 @@ public class GoGame {
private static void configureLogging() {
DOMConfigurator.configure("log4j.xml");
}
public static Player getColorToPlay(Player player, boolean playAsOpponent) {
if (playAsOpponent) {
if (player == Player.WHITE) {
return Player.BLACK;
} else if (player == Player.BLACK) {
return Player.WHITE;
} else {
return Player.NONE;
}
} else {
return player;
}
}
}

View File

@@ -0,0 +1,38 @@
package net.woodyfolsom.msproj;
public class Player {
public static final Player BLACK = new Player("BLACK", GameBoard.BLACK_STONE);
public static final Player NONE = new Player("NONE", GameBoard.EMPTY_INTERSECTION);
public static final Player WHITE = new Player("WHITE", GameBoard.WHITE_STONE);
private char stoneSymbol;
private String name;
private Player(String name, char stoneSymbol) {
this.name = name;
this.stoneSymbol = stoneSymbol;
}
public static Player getInstance(String stoneSymbol) {
if ("b".equals(stoneSymbol)) {
return Player.BLACK;
} else if ("w".equals(stoneSymbol)) {
return Player.WHITE;
} else {
return Player.NONE;
}
}
public char getStoneSymbol() {
return stoneSymbol;
}
public boolean isNone() {
return "NONE".equals(name);
}
@Override
public String toString() {
return name;
}
}

View File

@@ -2,12 +2,14 @@ package net.woodyfolsom.msproj.policy;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
public interface ActionGenerator {
public static final int ALL_ACTIONS = 0;
public List<String> getActions(GameConfig gameConfig, GameState gameState,
String color, int numActions);
public List<Action> getActions(GameConfig gameConfig, GameState gameState,
Player color, int numActions);
}

View File

@@ -2,55 +2,55 @@ package net.woodyfolsom.msproj.policy;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.GoGame;
import net.woodyfolsom.msproj.Player;
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 static final int DEFAULT_RECURSIVE_PLAYS = 1;
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
private String bestPick = Policy.PASS;
private Action bestPick = Action.PASS;
@Override
public String getAction(GameConfig gameConfig, GameState gameState,
String initialColor) {
public Action getAction(GameConfig gameConfig, GameState gameState,
Player player) {
int alpha = Integer.MIN_VALUE;
int beta = Integer.MAX_VALUE;
if ("b".equals(initialColor)) {
getMaxValue(gameConfig, gameState, initialColor, false,
if (player == Player.BLACK) {
getMaxValue(gameConfig, gameState, player, false,
DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta);
return bestPick;
} else if ("w".equals(initialColor)) {
getMinValue(gameConfig, gameState, initialColor, false,
} else if (player == Player.WHITE) {
getMinValue(gameConfig, gameState, player, false,
DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta);
return bestPick;
} else {
return Policy.PASS;
return Action.PASS;
}
}
private int getMaxValue(GameConfig gameConfig, GameState gameState,
String initialColor, boolean playAsOpponent, int recursionLevel,
Player initialColor, boolean playAsOpponent, int recursionLevel,
int alpha, int beta) {
if (terminalTest(recursionLevel)) {
return getUtility(gameConfig, gameState);
}
String colorPlaying = getColorToPlay(initialColor, playAsOpponent);
Player colorPlaying = GoGame.getColorToPlay(initialColor, playAsOpponent);
List<String> validMoves = validMoveGenerator.getActions(gameConfig,
List<Action> validMoves = validMoveGenerator.getActions(gameConfig,
gameState, colorPlaying, ActionGenerator.ALL_ACTIONS);
int value = Integer.MIN_VALUE;
for (String nextMove : validMoves) {
for (Action nextMove : validMoves) {
GameState nextState = new GameState(gameState);
if (!nextState.playStone(colorPlaying, nextMove)) {
@@ -78,20 +78,20 @@ public class AlphaBeta implements Policy {
}
private int getMinValue(GameConfig gameConfig, GameState gameState,
String initialColor, boolean playAsOpponent, int recursionLevel,
Player initialColor, boolean playAsOpponent, int recursionLevel,
int alpha, int beta) {
if (terminalTest(recursionLevel)) {
return getUtility(gameConfig, gameState);
}
String colorPlaying = getColorToPlay(initialColor, playAsOpponent);
Player colorPlaying = GoGame.getColorToPlay(initialColor, playAsOpponent);
List<String> validMoves = validMoveGenerator.getActions(gameConfig,
List<Action> validMoves = validMoveGenerator.getActions(gameConfig,
gameState, colorPlaying, ActionGenerator.ALL_ACTIONS);
int value = Integer.MAX_VALUE;
for (String nextMove : validMoves) {
for (Action nextMove : validMoves) {
GameState nextState = new GameState(gameState);
if (!nextState.playStone(colorPlaying, nextMove)) {
@@ -126,19 +126,4 @@ public class AlphaBeta implements Policy {
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;
}
}
}

View File

@@ -4,57 +4,66 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameState;
public abstract class GameTreeNode {
private GameConfig gameConfig;
public class GameTreeNode {
private GameState gameState;
private GameTreeNode parent;
private Map<String, GameTreeNode> children = new HashMap<String, GameTreeNode>();
private String player;
private int numVisits;
private int numWins;
private Map<Action, GameTreeNode> children = new HashMap<Action, GameTreeNode>();
public GameTreeNode(GameConfig gameConfig, GameState gameState,
String player) {
this.gameConfig = gameConfig;
public GameTreeNode(GameState gameState) {
this.gameState = gameState;
this.player = player;
}
public void addChild(String action, GameTreeNode child) {
public void addChild(Action action, GameTreeNode child) {
children.put(action, child);
child.parent = this;
}
public Set<String> getActions() {
public Set<Action> getActions() {
return children.keySet();
}
public GameTreeNode getChild(String action) {
public GameTreeNode getChild(Action action) {
return children.get(action);
}
public int getChildrenSize() {
public int getNumChildren() {
return children.size();
}
public GameConfig getGameConfig() {
return gameConfig;
}
public GameState getGameState() {
return gameState;
}
public GameTreeNode getParent() {
return parent;
public int getNumVisits() {
return numVisits;
}
public String getPlayer() {
return player;
public int getNumWins() {
return numWins;
}
public GameTreeNode getParent() {
return parent;
}
public boolean isRoot() {
return parent == null;
}
public boolean isTerminal() {
return children.size() == 0;
}
public void incrementVisits() {
numVisits++;
}
public void incrementWins() {
numWins++;
}
}

View File

@@ -1,47 +1,44 @@
package net.woodyfolsom.msproj.policy;
import java.util.ArrayList;
//import java.util.Arrays;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameScore;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.GoGame;
import net.woodyfolsom.msproj.Player;
import net.woodyfolsom.msproj.StateEvaluator;
//import org.apache.log4j.Logger;
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 getAction(GameConfig gameConfig, GameState gameState,
String color) {
public Action getAction(GameConfig gameConfig, GameState gameState,
Player color) {
MoveCandidate moveCandidate = findBestMinimaxResult(
DEFAULT_RECURSIVE_PLAYS * 2,
gameConfig, gameState, color, false, Policy.PASS);
gameConfig, gameState, color, false, Action.PASS);
return moveCandidate.move;
}
private MoveCandidate findBestMinimaxResult(int recursionLevels,
GameConfig gameConfig, GameState gameState,
String initialColor, boolean playAsOpponent, String bestPrevMove) {
Player initialColor, boolean playAsOpponent, Action bestPrevMove) {
StateEvaluator stateEvaluator = new StateEvaluator(gameConfig);
List<MoveCandidate> randomMoveCandidates = new ArrayList<MoveCandidate>();
String colorPlaying = getColorToPlay(initialColor, playAsOpponent);
Player colorPlaying = GoGame.getColorToPlay(initialColor, playAsOpponent);
List<String> validMoves = validMoveGenerator.getActions(gameConfig,
List<Action> validMoves = validMoveGenerator.getActions(gameConfig,
gameState, colorPlaying, ActionGenerator.ALL_ACTIONS);
for (String randomMove : validMoves) {
for (Action randomMove : validMoves) {
GameState stateCopy = new GameState(gameState);
stateCopy.playStone(colorPlaying, randomMove);
if (recursionLevels > 1) {
@@ -77,19 +74,4 @@ public class Minimax implements Policy {
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;
}
}
}

View File

@@ -1,61 +1,81 @@
package net.woodyfolsom.msproj.policy;
import java.util.ArrayList;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
public abstract class MonteCarlo implements Policy {
protected Policy movePolicy;
protected long searchTimeLimit;
protected volatile long elapsedTime = 0L;
public MonteCarlo(Policy movePolicy, long searchTimeLimit) {
this.movePolicy = movePolicy;
this.searchTimeLimit = searchTimeLimit;
}
public abstract MonteCarloTreeNode descend(MonteCarloTreeNode node);
/**
* Descend the tree from the specified node and return a list of nodes to grow.
*
* @param node
* @return
*/
public abstract List<GameTreeNode> descend(GameTreeNode node);
@Override
public String getAction(GameConfig gameConfig, GameState gameState,
String initialColor) {
long initialTime = System.currentTimeMillis();
public Action getAction(GameConfig gameConfig, GameState gameState,
Player initialColor) {
long startTime = 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;
GameTreeNode rootNode = new GameTreeNode(gameState);
MonteCarloTreeNode rootNode = new MonteCarloTreeNode(gameConfig, gameState, initialColor);
MonteCarloTreeNode selectedNode;
while (System.currentTimeMillis() - initialTime < searchTimeLimit) {
do {
//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);
List<GameTreeNode> selectedNodes = descend(rootNode);
List<GameTreeNode> newLeaves = new ArrayList<GameTreeNode>();
for (GameTreeNode selectedNode: selectedNodes) {
for (GameTreeNode newLeaf : grow(selectedNode)) {
newLeaves.add(newLeaf);
}
}
return bestMove;
for (GameTreeNode newLeaf : newLeaves) {
int reward = rollout(newLeaf);
update(newLeaf, reward);
}
public abstract MonteCarloTreeNode grow(MonteCarloTreeNode node);
elapsedTime = System.currentTimeMillis() - startTime;
} while (elapsedTime < searchTimeLimit);
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
return getBestAction(rootNode);
}
} else {
return color;
public long getElapsedTime() {
return elapsedTime;
}
public abstract Action getBestAction(GameTreeNode node);
public abstract List<GameTreeNode> grow(GameTreeNode node);
public abstract int rollout(GameTreeNode node);
public abstract void update(GameTreeNode node, int reward);
public long getSearchTimeLimit() {
return searchTimeLimit;
}
public int doRollout() {
return 0;
}
}

View File

@@ -1,30 +0,0 @@
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;
}
}

View File

@@ -1,5 +1,9 @@
package net.woodyfolsom.msproj.policy;
import java.util.ArrayList;
import java.util.List;
import net.woodyfolsom.msproj.Action;
public class MonteCarloUCT extends MonteCarlo {
@@ -8,25 +12,63 @@ public class MonteCarloUCT extends MonteCarlo {
}
@Override
public MonteCarloTreeNode descend(MonteCarloTreeNode node) {
public List<GameTreeNode> descend(GameTreeNode node) {
double bestScore = (double) node.getNumWins() / node.getNumVisits();
GameTreeNode bestNode = node;
//This appears slightly redundant with getBestAction() but it is not -
//descend() may pick the current node rather than a child to expand (if a child has a good score but high/low uncertainty)
//but getBestAction specifically asks for the optimum action to take from the current node,
//even if it results in a worse next state.
for (Action action : node.getActions()) {
GameTreeNode childNode = node.getChild(action);
double childScore = (double) childNode.getNumWins() / childNode.getNumVisits();
if (childScore >= bestScore) {
bestScore = childScore;
bestNode = childNode;
}
}
if (bestNode == node) {
List<GameTreeNode> bestNodeList = new ArrayList<GameTreeNode>();
bestNodeList.add(bestNode);
return bestNodeList;
} else {
return descend(bestNode);
}
}
@Override
public Action getBestAction(GameTreeNode node) {
Action bestAction = Action.NONE;
double bestScore = Double.NEGATIVE_INFINITY;
for (Action action : node.getActions()) {
GameTreeNode childNode = node.getChild(action);
double childScore = (double) childNode.getNumWins() / childNode.getNumVisits();
if (childScore >= bestScore) {
bestScore = childScore;
bestAction = action;
}
}
return bestAction;
}
@Override
public List<GameTreeNode> grow(GameTreeNode 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) {
public int rollout(GameTreeNode node) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void update(MonteCarloTreeNode node, int reward) {
public void update(GameTreeNode node, int reward) {
// TODO Auto-generated method stub
}

View File

@@ -1,12 +1,13 @@
package net.woodyfolsom.msproj.policy;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameScore;
public class MoveCandidate {
public final String move;
public final Action move;
public final GameScore score;
public MoveCandidate(String move, GameScore score) {
public MoveCandidate(Action move, GameScore score) {
this.move = move;
this.score = score;
}

View File

@@ -1,10 +1,11 @@
package net.woodyfolsom.msproj.policy;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
public interface Policy {
static final String PASS = "PASS";
public String getAction(GameConfig gameConfig, GameState gameState, String color);
public Action getAction(GameConfig gameConfig, GameState gameState, Player player);
}

View File

@@ -3,8 +3,10 @@ package net.woodyfolsom.msproj.policy;
import java.util.ArrayList;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
public class RandomMovePolicy implements Policy {
@@ -12,14 +14,15 @@ public class RandomMovePolicy implements Policy {
/**
* Does NOT modify the gameState.
*/
public String getAction(GameConfig gameConfig, GameState gameState,
String color) {
public Action getAction(GameConfig gameConfig, GameState gameState,
Player color) {
GameState gameStateCopy = new GameState(gameState);
List<String> emptyCoordinates = gameStateCopy.getEmptyCoords();
while (emptyCoordinates.size() > 0) {
String randomMove = emptyCoordinates
.get((int) (Math.random() * emptyCoordinates.size()));
Action randomMove = Action.getInstance(emptyCoordinates
.get((int) (Math.random() * emptyCoordinates.size())));
if (gameStateCopy.playStone(color, randomMove)) {
return randomMove;
} else {
@@ -27,7 +30,7 @@ public class RandomMovePolicy implements Policy {
}
}
return PASS;
return Action.PASS;
}
/**
@@ -42,15 +45,15 @@ public class RandomMovePolicy implements Policy {
*
* @return
*/
public List<String> genMoves(GameConfig gameConfig, GameState gameState,
String color, int nMoves) {
public List<Action> genMoves(GameConfig gameConfig, GameState gameState,
Player color, int nMoves) {
GameState gameStateCopy = new GameState(gameState);
List<String> emptyCoordinates = gameStateCopy.getEmptyCoords();
List<String> randomMoves = new ArrayList<String>();
List<Action> randomMoves = new ArrayList<Action>();
while (emptyCoordinates.size() > 0 && randomMoves.size() < nMoves) {
String randomMove = emptyCoordinates
.get((int) (Math.random() * emptyCoordinates.size()));
Action randomMove = Action.getInstance(emptyCoordinates
.get((int) (Math.random() * emptyCoordinates.size())));
if (gameStateCopy.playStone(color, randomMove)) {
randomMoves.add(randomMove);
}
@@ -58,7 +61,7 @@ public class RandomMovePolicy implements Policy {
}
if (randomMoves.size() == 0) {
randomMoves.add(PASS);
randomMoves.add(Action.PASS);
}
return randomMoves;

View File

@@ -3,8 +3,10 @@ package net.woodyfolsom.msproj.policy;
import java.util.ArrayList;
import java.util.List;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
//import org.apache.log4j.Logger;
@@ -12,23 +14,24 @@ public class ValidMoveGenerator implements ActionGenerator {
//private static final Logger LOGGER = Logger.getLogger(ValidMoveGenerator.class.getName());
@Override
public List<String> getActions(GameConfig gameConfig, GameState gameState,
String color, int nMoves) {
public List<Action> getActions(GameConfig gameConfig, GameState gameState,
Player color, int nMoves) {
GameState gameStateCopy = new GameState(gameState);
List<String> emptyCoordinates = gameStateCopy.getEmptyCoords();
List<String> validMoves = new ArrayList<String>();
List<Action> validMoves = new ArrayList<Action>();
while (emptyCoordinates.size() > 0) {
String nextMove = emptyCoordinates.remove(emptyCoordinates.size()-1);
Action nextMove = Action.getInstance(emptyCoordinates.remove(emptyCoordinates.size()-1));
if (gameStateCopy.playStone(color, nextMove)) {
validMoves.add(nextMove);
gameStateCopy = new GameState(gameState); // play successful? regenerate copy of gameState
}
}
//Passing is always a VALID move. It may not be a GOOD move.
if (validMoves.size() == 0) {
validMoves.add(Policy.PASS);
validMoves.add(Action.PASS);
}
return validMoves;

View File

@@ -4,27 +4,21 @@ 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 {
@Test
public void testCapture() {
GameState gameState = new GameState(5);
gameState.playStone('A', 2, GameBoard.BLACK_STONE);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
gameState.playStone('B', 1, GameBoard.BLACK_STONE);
assertTrue(gameState.playStone('B', 2, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("B2")));
assertEquals(0,gameState.getBlackPrisoners());
assertEquals(0,gameState.getWhitePrisoners());
assertTrue(gameState.playStone('C', 2, GameBoard.BLACK_STONE));
assertTrue(gameState.playStone(Player.BLACK, Action.getInstance("C2")));
assertEquals(1,gameState.getBlackPrisoners());
assertEquals(0,gameState.getWhitePrisoners());
@@ -37,25 +31,25 @@ public class CaptureTest {
GameConfig gameConfig = new GameConfig();
GameState gameState = new GameState(5);
gameState.playStone('A', 2, GameBoard.BLACK_STONE);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
gameState.playStone('B', 1, GameBoard.BLACK_STONE);
gameState.playStone('C', 4, GameBoard.BLACK_STONE);
gameState.playStone('D', 3, GameBoard.BLACK_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.BLACK, Action.getInstance("C4"));
gameState.playStone(Player.BLACK, Action.getInstance("D3"));
assertTrue(gameState.playStone('B', 2, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone('C', 3, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("B2")));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("C3")));
assertEquals(0,gameState.getBlackPrisoners());
assertEquals(0,gameState.getWhitePrisoners());
assertTrue(gameState.playStone('C', 2, GameBoard.BLACK_STONE));
assertTrue(gameState.playStone(Player.BLACK, Action.getInstance("C2")));
assertEquals(2,gameState.getBlackPrisoners());
assertEquals(0,gameState.getWhitePrisoners());
assertFalse(gameState.playStone('B', 2, GameBoard.WHITE_STONE));
assertFalse(gameState.playStone('C', 3, GameBoard.WHITE_STONE));
assertFalse(gameState.playStone(Player.WHITE, Action.getInstance("B2")));
assertFalse(gameState.playStone(Player.WHITE, Action.getInstance("C3")));
System.out.println(gameState);
@@ -67,20 +61,21 @@ public class CaptureTest {
public void testCaptureFromEye() {
GameState gameState = new GameState(5);
gameState.playStone('A', 1, GameBoard.BLACK_STONE);
gameState.playStone('B', 2, GameBoard.BLACK_STONE);
gameState.playStone('C', 1, GameBoard.BLACK_STONE);
gameState.playStone('A', 2, GameBoard.WHITE_STONE);
gameState.playStone('B', 3, GameBoard.WHITE_STONE);
gameState.playStone('C', 2, GameBoard.WHITE_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("A1"));
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
gameState.playStone(Player.BLACK, Action.getInstance("C1"));
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B3"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
//This capture should be allowed.
assertTrue("Capture from within single eye should have been allowed but move was rejected.",
gameState.playStone('B', 1, GameBoard.WHITE_STONE));
assertEquals(0,gameState.getBlackPrisoners());
assertEquals(2,gameState.getWhitePrisoners());
System.out.println("State before WHITE move: ");
System.out.println(gameState);
assertTrue("Capture from within single eye should have been allowed but move was rejected.",
gameState.playStone(Player.WHITE, Action.getInstance("B1")));
assertEquals("BLACK should have 0 prisoners.",0,gameState.getBlackPrisoners());
assertEquals("WHITE should have 2 prisoners.",2,gameState.getWhitePrisoners());
}
}

View File

@@ -3,9 +3,6 @@ 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 {
@@ -13,53 +10,57 @@ public class IllegalMoveTest {
@Test
public void testIllegalMoveOnOwnStone() {
GameState gameState = new GameState(5);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
assertFalse(gameState.playStone('B', 3, GameBoard.BLACK_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
assertFalse(gameState.playStone(Player.BLACK, Action.getInstance("B3")));
}
@Test
public void testIllegalMoveOnOtherStone() {
GameState gameState = new GameState(5);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
assertFalse(gameState.playStone('B', 3, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
assertFalse(gameState.playStone(Player.WHITE, Action.getInstance("B3")));
}
@Test
public void testIllegalMoveNoLiberties() {
GameState gameState = new GameState(5);
gameState.playStone('A', 2, GameBoard.BLACK_STONE);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
gameState.playStone('B', 1, GameBoard.BLACK_STONE);
gameState.playStone('C', 2, GameBoard.BLACK_STONE);
assertFalse(gameState.playStone('B', 2, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
System.out.println(gameState);
assertFalse(gameState.playStone(Player.WHITE, Action.getInstance("B2")));
System.out.println(gameState);
}
@Test
public void testIllegalMoveFormsTrappedGroup() {
GameState gameState = new GameState(9);
gameState.playStone('A', 5, GameBoard.BLACK_STONE);
gameState.playStone('B', 6, GameBoard.BLACK_STONE);
gameState.playStone('B', 7, GameBoard.BLACK_STONE);
gameState.playStone('A', 8, GameBoard.BLACK_STONE);
assertTrue(gameState.playStone('A', 6, GameBoard.WHITE_STONE));
assertFalse(gameState.playStone('A', 7, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("A5"));
gameState.playStone(Player.BLACK, Action.getInstance("B6"));
gameState.playStone(Player.BLACK, Action.getInstance("B7"));
gameState.playStone(Player.BLACK, Action.getInstance("A8"));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("A6")));
assertFalse(gameState.playStone(Player.WHITE, Action.getInstance("A7")));
System.out.println(gameState);
}
@Test
public void testIllegalMoveFormsTrappedGroup2() {
GameState gameState = new GameState(9);
gameState.playStone('G', 1, GameBoard.BLACK_STONE);
gameState.playStone('H', 2, GameBoard.BLACK_STONE);
gameState.playStone('H', 3, GameBoard.BLACK_STONE);
gameState.playStone('J', 4, GameBoard.BLACK_STONE);
gameState.playStone('A', 8, GameBoard.BLACK_STONE);
assertTrue(gameState.playStone('H', 1, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone('J', 2, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone('J', 3, GameBoard.WHITE_STONE));
System.out.println(gameState);
assertFalse(gameState.playStone('J', 1, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("G1"));
gameState.playStone(Player.BLACK, Action.getInstance("H2"));
gameState.playStone(Player.BLACK, Action.getInstance("H3"));
gameState.playStone(Player.BLACK, Action.getInstance("J4"));
gameState.playStone(Player.BLACK, Action.getInstance("A8"));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("H1")));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("J2")));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("J3")));
System.out.println("State before move: ");
System.out.println(gameState);
assertFalse("Play by WHITE at J1 should have failed.",gameState.playStone(Player.WHITE, Action.getInstance("J1")));
}
}

View File

@@ -2,19 +2,16 @@ 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 {
@Test
public void testLegalMove1Liberty() {
GameState gameState = new GameState(5);
gameState.playStone('A', 2, GameBoard.BLACK_STONE);
gameState.playStone('B', 3, GameBoard.BLACK_STONE);
gameState.playStone('B', 1, GameBoard.BLACK_STONE);
assertTrue(gameState.playStone('B', 2, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
assertTrue(gameState.playStone(Player.WHITE, Action.getInstance("B2")));
System.out.println(gameState);
}
}

View File

@@ -3,87 +3,85 @@ 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;
public class StateEvaluatorTest {
GameConfig gameConfig = new GameConfig();
@Test
public void testScoreEmptyBoard() {
GameState gameState = new GameState(5);
GameScore gameScore = new StateEvaluator(gameConfig).scoreGame(gameState);
GameScore gameScore = new StateEvaluator(gameConfig)
.scoreGame(gameState);
assertEquals(0.0,gameScore.getWhiteScore(),0.5);
assertEquals(0.0,gameScore.getBlackScore(),0.5);
assertEquals(0.0, gameScore.getWhiteScore(), 0.5);
assertEquals(0.0, gameScore.getBlackScore(), 0.5);
}
@Test
public void testScoreFirstMove() {
GameState gameState = new GameState(5);
gameState.playStone('B',3,GameBoard.BLACK_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
GameScore gameScore = new StateEvaluator(gameConfig).scoreGame(gameState);
GameScore gameScore = new StateEvaluator(gameConfig)
.scoreGame(gameState);
System.out.println(gameScore.getScoreReport());
assertEquals(0.0,gameScore.getWhiteScore(),0.5);
assertEquals(25.0,gameScore.getBlackScore(),0.5);
assertEquals(0.0, gameScore.getWhiteScore(), 0.5);
assertEquals(25.0, gameScore.getBlackScore(), 0.5);
}
@Test
public void testScoreTiedAtMove2() {
GameState gameState = new GameState(5);
gameState.playStone('B',3,GameBoard.BLACK_STONE);
gameState.playStone('A',1,GameBoard.WHITE_STONE);
GameScore gameScore = new StateEvaluator(gameConfig).scoreGame(gameState);
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.WHITE, Action.getInstance("A1"));
GameScore gameScore = new StateEvaluator(gameConfig)
.scoreGame(gameState);
System.out.println(gameScore.getScoreReport());
assertEquals(1.0,gameScore.getWhiteScore(),0.5);
assertEquals(1.0,gameScore.getBlackScore(),0.5);
assertEquals(1.0, gameScore.getWhiteScore(), 0.5);
assertEquals(1.0, gameScore.getBlackScore(), 0.5);
}
@Test
public void testScoreTerritory() {
GameState gameState = new GameState(5);
gameState.playStone('A',2,GameBoard.BLACK_STONE);
gameState.playStone('B',3,GameBoard.BLACK_STONE);
gameState.playStone('C',2,GameBoard.BLACK_STONE);
gameState.playStone('B',1,GameBoard.BLACK_STONE);
gameState.playStone('E',5,GameBoard.WHITE_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("E5"));
System.out.println(gameState);
GameScore gameScore = new StateEvaluator(gameConfig).scoreGame(gameState);
GameScore gameScore = new StateEvaluator(gameConfig)
.scoreGame(gameState);
System.out.println(gameScore.getScoreReport());
assertEquals(1.0,gameScore.getWhiteScore(),0.5);
assertEquals(6.0,gameScore.getBlackScore(),0.5);
//Black should be up by 5 if Black's territory at A1 & B2 is scored correctly.
assertEquals(1.0, gameScore.getWhiteScore(), 0.5);
assertEquals(6.0, gameScore.getBlackScore(), 0.5);
// Black should be up by 5 if Black's territory at A1 & B2 is scored
// correctly.
}
@Test
public void testCaptureAggScore() {
GameState gameState = new GameState(9);
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);
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
GameState moveToA1 = new GameState(gameState);
GameState capAtB3 = new GameState(gameState);
moveToA1.playStone("w","A1");
capAtB3.playStone("w", "B3");
moveToA1.playStone(Player.WHITE, Action.getInstance("A1"));
capAtB3.playStone(Player.WHITE, Action.getInstance("B3"));
System.out.println(moveToA1);
System.out.println(capAtB3);
@@ -94,7 +92,7 @@ public class StateEvaluatorTest {
System.out.println("Score at A1: " + scoreA1);
System.out.println("Score at B3: " + scoreB3);
//moving as white, lower is better
// moving as white, lower is better
assertTrue(scoreA1 > scoreB3);
}
}

View File

@@ -1,9 +1,5 @@
package net.woodyfolsom.msproj;
import net.woodyfolsom.msproj.GameBoard;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.TerritoryMarker;
import org.junit.Test;
public class TerritoryFinderTest {
@@ -11,11 +7,11 @@ public class TerritoryFinderTest {
public void testMarkTerritory() {
GameState gameState = new GameState(5);
gameState.playStone('A',2,GameBoard.BLACK_STONE);
gameState.playStone('B',3,GameBoard.BLACK_STONE);
gameState.playStone('C',2,GameBoard.BLACK_STONE);
gameState.playStone('B',1,GameBoard.BLACK_STONE);
gameState.playStone('E',5,GameBoard.WHITE_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B3"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("E5"));
TerritoryMarker.markTerritory(gameState.getGameBoard());
System.out.println(gameState);

View File

@@ -1,12 +1,10 @@
package net.woodyfolsom.msproj.policy;
import static org.junit.Assert.assertEquals;
import net.woodyfolsom.msproj.GameBoard;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.policy.AlphaBeta;
import net.woodyfolsom.msproj.policy.Policy;
import net.woodyfolsom.msproj.Player;
import org.junit.Test;
@@ -15,43 +13,40 @@ public class AlphaBetaTest {
public void testGenmoveAsW() {
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);
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
Action move = treeSearch.getAction(new GameConfig(), gameState, Player.WHITE);
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);
assertEquals("Expected B3 but was: " + move, Action.getInstance("B3"), move);
gameState.playStone(Player.WHITE, move);
System.out.println("Final board state:");
System.out.println(gameState);
assertEquals(Policy.PASS,
treeSearch.getAction(new GameConfig(), gameState, "?"));
}
@Test
public void testGenmoveAsB() {
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);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.WHITE, Action.getInstance("B2"));
Action move = treeSearch.getAction(new GameConfig(), gameState, Player.BLACK);
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);
assertEquals("Expected B3 but was: " + move, Action.getInstance("B3"), move);
gameState.playStone(Player.BLACK, move);
System.out.println("Final board state:");
System.out.println(gameState);
assertEquals(Policy.PASS,
treeSearch.getAction(new GameConfig(), gameState, "?"));
}
}

View File

@@ -1,33 +1,52 @@
package net.woodyfolsom.msproj.policy;
import static org.junit.Assert.assertEquals;
import net.woodyfolsom.msproj.GameBoard;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.policy.Policy;
import net.woodyfolsom.msproj.Player;
import org.junit.Test;
public class MinimaxTest {
@Test
public void testGenmove() {
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);
public void testGenmoveAsW() {
Policy treeSearch = new Minimax();
GameState gameState = new GameState(6);
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
String move = moveGenerator.getAction(new GameConfig(), gameState, "w");
System.out.println("Generated move: " + move);
gameState.playStone("w", move);
Action move = treeSearch.getAction(new GameConfig(), gameState,
Player.WHITE);
System.out.println(gameState);
assertEquals(Policy.PASS,moveGenerator.getAction(new GameConfig(), gameState, "?"));
System.out.println("Generated move: " + move);
assertEquals("Expected B3 but was: " + move, "B3", move);
gameState.playStone(Player.WHITE, move);
System.out.println(gameState);
}
@Test
public void testGenmoveAsB() {
Policy treeSearch = new Minimax();
GameState gameState = new GameState(6);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.WHITE, Action.getInstance("B2"));
Action move = treeSearch.getAction(new GameConfig(), gameState,
Player.BLACK);
System.out.println(gameState);
System.out.println("Generated move: " + move);
assertEquals("Expected B3 but was: " + move, "B3", move);
gameState.playStone(Player.BLACK, move);
System.out.println(gameState);
}

View File

@@ -0,0 +1,53 @@
package net.woodyfolsom.msproj.policy;
import static org.junit.Assert.assertEquals;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
import net.woodyfolsom.msproj.policy.Policy;
import org.junit.Test;
public class MonteCarloUCTTest {
@Test
public void testGenmoveAsW() {
Policy treeSearch = new MonteCarloUCT(new RandomMovePolicy(),2000L);
GameState gameState = new GameState(6);
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
Action move = treeSearch.getAction(new GameConfig(), gameState, Player.WHITE);
System.out.println(gameState);
System.out.println("Generated move: " + move);
assertEquals("Expected B3 but was: " + move, "B3", move);
gameState.playStone(Player.WHITE, move);
System.out.println(gameState);
}
@Test
public void testGenmoveAsB() {
Policy treeSearch = new MonteCarloUCT(new RandomMovePolicy(),2000L);
GameState gameState = new GameState(6);
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.WHITE, Action.getInstance("B2"));
Action move = treeSearch.getAction(new GameConfig(), gameState, Player.BLACK);
System.out.println(gameState);
System.out.println("Generated move: " + move);
assertEquals("Expected B3 but was: " + move, "B3", move);
gameState.playStone(Player.BLACK, move);
System.out.println(gameState);
}
}

View File

@@ -1,53 +1,56 @@
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.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.policy.Policy;
import net.woodyfolsom.msproj.policy.RandomMovePolicy;
import net.woodyfolsom.msproj.Player;
import org.junit.Test;
public class RandomTest {
@Test
public void testGenmove() {
@Test(expected = IllegalArgumentException.class)
public void testGenmoveForNone() {
Policy moveGenerator = new RandomMovePolicy();
GameState gameState = new GameState(5);
moveGenerator.getAction(new GameConfig(), gameState, "b");
moveGenerator.getAction(new GameConfig(), gameState, Player.BLACK);
gameState = new GameState(5);
moveGenerator.getAction(new GameConfig(), gameState, "w");
moveGenerator.getAction(new GameConfig(), gameState, Player.WHITE);
assertEquals(Policy.PASS,moveGenerator.getAction(new GameConfig(), gameState, "?"));
System.out.println(gameState);
assertEquals(Action.PASS, moveGenerator.getAction(new GameConfig(), gameState, Player.NONE));
}
@Test
public void testAlternativeToIllegalMove() {
GameState gameState = new GameState(4);
gameState.playStone('A', 1, GameBoard.BLACK_STONE);
gameState.playStone('A', 2, GameBoard.BLACK_STONE);
gameState.playStone('A', 3, GameBoard.BLACK_STONE);
gameState.playStone('A', 4, GameBoard.BLACK_STONE);
gameState.playStone('B', 1, GameBoard.BLACK_STONE);
gameState.playStone('B', 2, GameBoard.BLACK_STONE);
gameState.playStone(Player.BLACK, Action.getInstance("A1"));
gameState.playStone(Player.BLACK, Action.getInstance("A2"));
gameState.playStone(Player.BLACK, Action.getInstance("A3"));
gameState.playStone(Player.BLACK, Action.getInstance("A4"));
gameState.playStone(Player.BLACK, Action.getInstance("B1"));;
gameState.playStone(Player.BLACK, Action.getInstance("B2"));
//gameState.playStone('B', 3, GameBoard.BLACK_STONE);
gameState.playStone('B', 4, GameBoard.BLACK_STONE);
gameState.playStone('C', 2, GameBoard.BLACK_STONE);
gameState.playStone('C', 3, GameBoard.BLACK_STONE);
gameState.playStone('C', 4, GameBoard.BLACK_STONE);
gameState.playStone('D', 4, GameBoard.BLACK_STONE);
assertTrue(gameState.playStone('C', 1, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone('D', 2, GameBoard.WHITE_STONE));
assertTrue(gameState.playStone('D', 3, GameBoard.WHITE_STONE));
gameState.playStone(Player.BLACK, Action.getInstance("B4"));
gameState.playStone(Player.BLACK, Action.getInstance("C2"));
gameState.playStone(Player.BLACK, Action.getInstance("C3"));
gameState.playStone(Player.BLACK, Action.getInstance("C4"));
gameState.playStone(Player.BLACK, Action.getInstance("D4"));
gameState.playStone(Player.WHITE, Action.getInstance("C1"));
gameState.playStone(Player.WHITE, Action.getInstance("D2"));
gameState.playStone(Player.WHITE, Action.getInstance("D3"));
System.out.println("State before random WHITE move selection:");
System.out.println(gameState);
//This is correct - checked vs. MFOG
assertEquals("B3", new RandomMovePolicy().getAction(new GameConfig(), gameState, "w"));
assertEquals(Action.getInstance("B3"), new RandomMovePolicy().getAction(new GameConfig(), gameState, Player.WHITE));
System.out.println(gameState);
}
}

View File

@@ -1,13 +1,14 @@
package net.woodyfolsom.msproj.policy;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.List;
import net.woodyfolsom.msproj.GameBoard;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.policy.ValidMoveGenerator;
import net.woodyfolsom.msproj.Player;
import org.junit.Test;
@@ -26,18 +27,22 @@ public class ValidMoveGeneratorTest {
A B C D E
*/
GameState gameState = new GameState(5);
gameState.playStone('A', 2, GameBoard.WHITE_STONE);
gameState.playStone('B', 1, GameBoard.WHITE_STONE);
gameState.playStone('B', 4, GameBoard.WHITE_STONE);
gameState.playStone('C', 2, GameBoard.WHITE_STONE);
assertFalse(gameState.playStone('A', 1, GameBoard.BLACK_STONE));
gameState.playStone(Player.WHITE, Action.getInstance("A2"));
gameState.playStone(Player.WHITE, Action.getInstance("B1"));
gameState.playStone(Player.WHITE, Action.getInstance("B4"));
gameState.playStone(Player.WHITE, Action.getInstance("C2"));
assertFalse(gameState.playStone(Player.BLACK, Action.getInstance("A1")));
List<Action> validMoves = new ValidMoveGenerator().getActions(new GameConfig(), gameState, Player.BLACK,0);
List<String> validMoves = new ValidMoveGenerator().getActions(new GameConfig(), gameState, "b",0);
assertTrue(validMoves.size() > 0);
for (String vm : validMoves) {
for (Action vm : validMoves) {
System.out.println(vm);
}
assertFalse(validMoves.contains("A1"));
assertFalse(validMoves.contains(Action.getInstance("A1")));
System.out.println(gameState);
}