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.
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
package cs6601.p1;
|
||||
|
||||
public class GameController {
|
||||
|
||||
}
|
||||
@@ -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<String> validMoves = validMoveGenerator.genMoves(gameConfig,
|
||||
gameState, colorPlaying, MoveGenerator.ALL_MOVES);
|
||||
|
||||
int value = Integer.MIN_VALUE;
|
||||
|
||||
//Map<Integer,String> firstMovesByScore = new HashMap<Integer,String> ();
|
||||
|
||||
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<String> validMoves = validMoveGenerator.genMoves(gameConfig,
|
||||
gameState, colorPlaying, MoveGenerator.ALL_MOVES);
|
||||
|
||||
int value = Integer.MAX_VALUE;
|
||||
|
||||
//Map<Integer,String> firstMovesByScore = new HashMap<Integer,String> ();
|
||||
|
||||
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<String> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<MoveCandidate> randomMoveCandidates = new ArrayList<MoveCandidate>();
|
||||
|
||||
String colorPlaying = getColorToPlay(initialColor, playAsOpponent);
|
||||
|
||||
List<String> 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<String> genMoves(GameConfig gameConfig, GameState gameState,
|
||||
String color, int nMoves) {
|
||||
String[] pass = new String[] {PASS};
|
||||
return Arrays.asList(pass);
|
||||
}
|
||||
}
|
||||
@@ -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<String> genMoves(GameConfig gameConfig, GameState gameState, String color, int nMoves);
|
||||
}
|
||||
@@ -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 };
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
public class GameConfig {
|
||||
private double komi;
|
||||
5
src/net/woodyfolsom/msproj/GameController.java
Normal file
5
src/net/woodyfolsom/msproj/GameController.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
public class GameController {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
|
||||
public class GameScore {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
public class GtpClient {
|
||||
|
||||
@@ -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) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
public class StateEvaluator {
|
||||
private final GameConfig gameConfig;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cs6601.p1;
|
||||
package net.woodyfolsom.msproj;
|
||||
|
||||
public class TerritoryMarker {
|
||||
public static final char BLACK_TERRITORY = 'x';
|
||||
27
src/net/woodyfolsom/msproj/ZobristHashGenerator.java
Normal file
27
src/net/woodyfolsom/msproj/ZobristHashGenerator.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/net/woodyfolsom/msproj/policy/ActionGenerator.java
Normal file
13
src/net/woodyfolsom/msproj/policy/ActionGenerator.java
Normal file
@@ -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<String> getActions(GameConfig gameConfig, GameState gameState,
|
||||
String color, int numActions);
|
||||
}
|
||||
144
src/net/woodyfolsom/msproj/policy/AlphaBeta.java
Normal file
144
src/net/woodyfolsom/msproj/policy/AlphaBeta.java
Normal file
@@ -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<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/net/woodyfolsom/msproj/policy/GameTreeNode.java
Normal file
60
src/net/woodyfolsom/msproj/policy/GameTreeNode.java
Normal file
@@ -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<String, GameTreeNode> children = new HashMap<String, GameTreeNode>();
|
||||
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<String> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<String> validMoves = validMoveGenerator.genMoves(gameConfig,
|
||||
gameState, colorPlaying, MoveGenerator.ALL_MOVES);
|
||||
List<String> 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<String> 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);
|
||||
}
|
||||
}
|
||||
61
src/net/woodyfolsom/msproj/policy/MonteCarlo.java
Normal file
61
src/net/woodyfolsom/msproj/policy/MonteCarlo.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java
Normal file
30
src/net/woodyfolsom/msproj/policy/MonteCarloTreeNode.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
34
src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java
Normal file
34
src/net/woodyfolsom/msproj/policy/MonteCarloUCT.java
Normal file
@@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
10
src/net/woodyfolsom/msproj/policy/Policy.java
Normal file
10
src/net/woodyfolsom/msproj/policy/Policy.java
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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<String> emptyCoordinates = gameStateCopy.getEmptyCoords();
|
||||
@@ -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());
|
||||
public class ValidMoveGenerator implements ActionGenerator {
|
||||
//private static final Logger LOGGER = Logger.getLogger(ValidMoveGenerator.class.getName());
|
||||
|
||||
@Override
|
||||
public String genMove(GameConfig gameConfig, GameState gameState,
|
||||
String color) {
|
||||
LOGGER.info("ValidMoveGenerator genMove() stub returning PASS");
|
||||
return PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> genMoves(GameConfig gameConfig, GameState gameState,
|
||||
public List<String> 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;
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
|
||||
17
test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java
Normal file
17
test/net/woodyfolsom/msproj/ZobristHashGeneratorTest.java
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,26 @@
|
||||
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);
|
||||
@@ -27,19 +29,20 @@ public class AlphaBetaTest {
|
||||
|
||||
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);
|
||||
@@ -48,6 +51,7 @@ public class AlphaBetaTest {
|
||||
|
||||
System.out.println(gameState);
|
||||
|
||||
assertEquals(MoveGenerator.PASS,moveGenerator.genMove(new GameConfig(), gameState, "?"));
|
||||
assertEquals(Policy.PASS,
|
||||
treeSearch.getAction(new GameConfig(), gameState, "?"));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<String> validMoves = new ValidMoveGenerator().genMoves(new GameConfig(), gameState, "b",0);
|
||||
List<String> validMoves = new ValidMoveGenerator().getActions(new GameConfig(), gameState, "b",0);
|
||||
assertTrue(validMoves.size() > 0);
|
||||
for (String vm : validMoves) {
|
||||
System.out.println(vm);
|
||||
Reference in New Issue
Block a user