Merge branch 'master' of woodyfolsom.net:/opt/git/cs8803p4
Conflicts: src/view/ParsedArgs.java
This commit is contained in:
@@ -12,6 +12,66 @@ public class Board {
|
|||||||
public static final int NUM_ROWS = 5;
|
public static final int NUM_ROWS = 5;
|
||||||
public static final int ROW_REMOVAL_SIZE = 3;
|
public static final int ROW_REMOVAL_SIZE = 3;
|
||||||
|
|
||||||
|
public static boolean isLegal(Board brd, CellPointer cp) {
|
||||||
|
if (cp.r < 0 || cp.r >= Board.NUM_ROWS || cp.c < 0
|
||||||
|
|| cp.c >= Board.NUM_COLS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean legal = (brd.getTile(cp.r, cp.c) == TileColor.NONE);
|
||||||
|
|
||||||
|
boolean rowUp = (cp.r - 1) >= 0;
|
||||||
|
boolean rowDown = (cp.r + 1) < Board.NUM_ROWS;
|
||||||
|
boolean colUp = (cp.c - 1) >= 0;
|
||||||
|
boolean colDown = (cp.c + 1) < Board.NUM_COLS;
|
||||||
|
|
||||||
|
// r-1 / c-1
|
||||||
|
if (rowUp && colUp
|
||||||
|
&& (brd.getTile(cp.r - 1, cp.c - 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r-1 / c
|
||||||
|
if (rowUp && (brd.getTile(cp.r - 1, cp.c) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r-1 / c+1
|
||||||
|
if (rowUp && colDown
|
||||||
|
&& (brd.getTile(cp.r - 1, cp.c + 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r / c-1
|
||||||
|
if (colUp && (brd.getTile(cp.r, cp.c - 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r / c+1
|
||||||
|
if (colDown && (brd.getTile(cp.r, cp.c + 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r+1 / c-1
|
||||||
|
if (rowDown && colUp
|
||||||
|
&& (brd.getTile(cp.r + 1, cp.c - 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r+1 / c
|
||||||
|
if (rowDown && (brd.getTile(cp.r + 1, cp.c) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// r+1 / c+1
|
||||||
|
if (rowDown && colDown
|
||||||
|
&& (brd.getTile(cp.r + 1, cp.c + 1) != TileColor.NONE)) {
|
||||||
|
return legal && true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return brd.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private final TileColor[][] board;
|
private final TileColor[][] board;
|
||||||
|
|
||||||
// a Ply is a play by 1 side. Increments each time setTile() is called.
|
// a Ply is a play by 1 side. Increments each time setTile() is called.
|
||||||
@@ -57,6 +117,19 @@ public class Board {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getEmptySpaces() {
|
||||||
|
int count = 0;
|
||||||
|
for (int r = 0; r < NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < NUM_COLS; c++) {
|
||||||
|
if (getTile(r, c) == TileColor.NONE) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
public TileColor getTile(int r, int c) {
|
public TileColor getTile(int r, int c) {
|
||||||
return board[r][c];
|
return board[r][c];
|
||||||
}
|
}
|
||||||
@@ -90,8 +163,8 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean playTile(CellPointer cp, TileColor tile) {
|
public boolean playTile(CellPointer cp, TileColor tile) {
|
||||||
if (board[cp.r][cp.c] != TileColor.NONE) {
|
if (!isLegal(this, cp)) {
|
||||||
return false; // illegal move
|
return false; // Illegal move.
|
||||||
}
|
}
|
||||||
|
|
||||||
board[cp.r][cp.c] = tile;
|
board[cp.r][cp.c] = tile;
|
||||||
@@ -247,4 +320,16 @@ public class Board {
|
|||||||
}
|
}
|
||||||
return sb1.toString();
|
return sb1.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isEmpty() {
|
||||||
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (getTile(r, c) != TileColor.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package model;
|
|||||||
import model.Board.TileColor;
|
import model.Board.TileColor;
|
||||||
import model.comPlayer.HumanPlayer;
|
import model.comPlayer.HumanPlayer;
|
||||||
import model.comPlayer.Player;
|
import model.comPlayer.Player;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
@@ -102,6 +103,9 @@ public class Referee implements Runnable {
|
|||||||
while (true) {
|
while (true) {
|
||||||
initGame();
|
initGame();
|
||||||
mf.updateBoard();
|
mf.updateBoard();
|
||||||
|
GameGoal goal = playerModel.getTargetScore();
|
||||||
|
System.out.println("Target: " + goal.getTargetScore());
|
||||||
|
computerPlayer.setGameGoal(goal);
|
||||||
play();
|
play();
|
||||||
getPlayerModel().logGame(getPlayerScore());
|
getPlayerModel().logGame(getPlayerScore());
|
||||||
|
|
||||||
@@ -128,7 +132,8 @@ public class Referee implements Runnable {
|
|||||||
int tile = 0;
|
int tile = 0;
|
||||||
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
for (int c = 0; c < Board.NUM_COLS; c++) {
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
move[tile] = (mv.getCell().r == r && mv.getCell().c == c);
|
move[tile + 4] = (mv.getCell().r == r && mv.getCell().c == c);
|
||||||
|
tile++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,12 +168,13 @@ public class Referee implements Runnable {
|
|||||||
System.out
|
System.out
|
||||||
.println("Interrupted while waiting for human to move!");
|
.println("Interrupted while waiting for human to move!");
|
||||||
} else {
|
} else {
|
||||||
|
getPlayerModel().getOutputNodes(getBoardState(board));
|
||||||
|
|
||||||
Move mv = humanPlayer.getMove(board, playerModel);
|
Move mv = humanPlayer.getMove(board, playerModel);
|
||||||
if (board.getTile(mv.getCell().r, mv.getCell().c) == TileColor.NONE) {
|
if (board.getTile(mv.getCell().r, mv.getCell().c) == TileColor.NONE) {
|
||||||
playToken(humanPlayer.getMove(board, playerModel));
|
playToken(humanPlayer.getMove(board, playerModel));
|
||||||
|
|
||||||
getPlayerModel().train(getBoardState(board),
|
getPlayerModel().train(getMoveArray(mv));
|
||||||
getMoveArray(mv));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
humanPlayer.denyMove();
|
humanPlayer.denyMove();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import model.Move;
|
|||||||
import model.comPlayer.generator.AlphaBetaMoveGenerator;
|
import model.comPlayer.generator.AlphaBetaMoveGenerator;
|
||||||
import model.comPlayer.generator.MonteCarloMoveGenerator;
|
import model.comPlayer.generator.MonteCarloMoveGenerator;
|
||||||
import model.comPlayer.generator.MoveGenerator;
|
import model.comPlayer.generator.MoveGenerator;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
import aima.core.environment.gridworld.GridCell;
|
import aima.core.environment.gridworld.GridCell;
|
||||||
import aima.core.environment.gridworld.GridWorld;
|
import aima.core.environment.gridworld.GridWorld;
|
||||||
@@ -24,6 +25,7 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
|
|
||||||
private BoardScorer boardScorer = new BoardScorer();
|
private BoardScorer boardScorer = new BoardScorer();
|
||||||
private boolean calculatePolicy = true;
|
private boolean calculatePolicy = true;
|
||||||
|
private GameGoal target = null;
|
||||||
private GridWorld<Double> gw = null;
|
private GridWorld<Double> gw = null;
|
||||||
private MarkovDecisionProcess<GridCell<Double>, GridWorldAction> mdp = null;
|
private MarkovDecisionProcess<GridCell<Double>, GridWorldAction> mdp = null;
|
||||||
private Policy<GridCell<Double>, GridWorldAction> policy = null;
|
private Policy<GridCell<Double>, GridWorldAction> policy = null;
|
||||||
@@ -42,7 +44,7 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
// take 10 turns to place 6 tiles
|
// take 10 turns to place 6 tiles
|
||||||
double defaultPenalty = -0.25;
|
double defaultPenalty = -0.25;
|
||||||
|
|
||||||
int maxScore = player.getTargetScore().getTargetScore();
|
int maxScore = target.getTargetScore();
|
||||||
int maxTiles = Board.NUM_COLS * Board.NUM_ROWS;
|
int maxTiles = Board.NUM_COLS * Board.NUM_ROWS;
|
||||||
|
|
||||||
gw = GridWorldFactory.createGridWorldForTileGame(maxTiles,
|
gw = GridWorldFactory.createGridWorldForTileGame(maxTiles,
|
||||||
@@ -75,19 +77,24 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
GridWorldAction action = policy.action(state);
|
GridWorldAction action = policy.action(state);
|
||||||
|
|
||||||
if (action == null || state == null) {
|
if (action == null || state == null) {
|
||||||
System.out.println("Board state outside of parameters of MDP. Reverting to failsafe behavior.");
|
System.out
|
||||||
|
.println("Board state outside of parameters of MDP. Reverting to failsafe behavior.");
|
||||||
action = GridWorldAction.RandomMove;
|
action = GridWorldAction.RandomMove;
|
||||||
}
|
}
|
||||||
System.out.println("Performing action " + action + " at state " + state + " per policy.");
|
System.out.println("Performing action " + action + " at state " + state
|
||||||
|
+ " per policy.");
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case AddTile:
|
case AddTile:
|
||||||
//System.out.println("Performing action #" + GridWorldAction.AddTile.ordinal());
|
// System.out.println("Performing action #" +
|
||||||
|
// GridWorldAction.AddTile.ordinal());
|
||||||
return abMoveGenerator.genMove(board, false);
|
return abMoveGenerator.genMove(board, false);
|
||||||
case CaptureThree:
|
case CaptureThree:
|
||||||
//System.out.println("Performing action #" + GridWorldAction.CaptureThree.ordinal());
|
// System.out.println("Performing action #" +
|
||||||
|
// GridWorldAction.CaptureThree.ordinal());
|
||||||
return mcMoveGenerator.genMove(board, false);
|
return mcMoveGenerator.genMove(board, false);
|
||||||
case RandomMove:
|
case RandomMove:
|
||||||
//System.out.println("Performing action #" + GridWorldAction.None.ordinal());
|
// System.out.println("Performing action #" +
|
||||||
|
// GridWorldAction.None.ordinal());
|
||||||
return mcMoveGenerator.genMove(board, false);
|
return mcMoveGenerator.genMove(board, false);
|
||||||
default:
|
default:
|
||||||
// System.out.println("Performing failsafe action");
|
// System.out.println("Performing failsafe action");
|
||||||
@@ -106,6 +113,11 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Alpha-Beta ComPlayer";
|
return "Adaptive ComPlayer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
this.target = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import model.Board;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.comPlayer.generator.AlphaBetaMoveGenerator;
|
import model.comPlayer.generator.AlphaBetaMoveGenerator;
|
||||||
import model.comPlayer.generator.MoveGenerator;
|
import model.comPlayer.generator.MoveGenerator;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class AlphaBetaComPlayer implements Player {
|
public class AlphaBetaComPlayer implements Player {
|
||||||
@@ -24,6 +25,12 @@ public class AlphaBetaComPlayer implements Player {
|
|||||||
return true; // always ready to play a random valid move
|
return true; // always ready to play a random valid move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Alpha-Beta ComPlayer";
|
return "Alpha-Beta ComPlayer";
|
||||||
|
|||||||
44
src/model/comPlayer/ComboPlayer.java
Normal file
44
src/model/comPlayer/ComboPlayer.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package model.comPlayer;
|
||||||
|
|
||||||
|
import model.Board;
|
||||||
|
import model.Move;
|
||||||
|
import model.comPlayer.generator.AlphaBetaMoveGenerator;
|
||||||
|
import model.comPlayer.generator.NeuralNetworkMoveGenerator;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
|
public class ComboPlayer implements Player {
|
||||||
|
|
||||||
|
private final AlphaBetaMoveGenerator abGen = new AlphaBetaMoveGenerator();
|
||||||
|
private NeuralNetworkMoveGenerator nnGen = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void denyMove() {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Move getMove(Board board, PlayerModel player) {
|
||||||
|
if (player.getHighScores()[2] == -1) {
|
||||||
|
return abGen.genMove(board, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (nnGen == null) {
|
||||||
|
nnGen = new NeuralNetworkMoveGenerator(player);
|
||||||
|
}
|
||||||
|
return nnGen.genMove(board, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// Nothing yet.
|
||||||
|
}
|
||||||
|
}
|
||||||
299
src/model/comPlayer/CountingPlayer.java
Normal file
299
src/model/comPlayer/CountingPlayer.java
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
package model.comPlayer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import model.Board;
|
||||||
|
import model.Board.TileColor;
|
||||||
|
import model.CellPointer;
|
||||||
|
import model.Move;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
|
public class CountingPlayer implements Player {
|
||||||
|
|
||||||
|
private static boolean causesConnection(Board board, Move m) {
|
||||||
|
|
||||||
|
CellPointer cell = m.getCell();
|
||||||
|
TileColor color = m.getColor();
|
||||||
|
boolean causes = false;
|
||||||
|
|
||||||
|
boolean oneUBlank = (cell.r - 1 >= 0)
|
||||||
|
&& board.getTile(cell.r - 1, cell.c) == TileColor.NONE;
|
||||||
|
boolean oneUColor = (cell.r - 1 >= 0)
|
||||||
|
&& board.getTile(cell.r - 1, cell.c) == color;
|
||||||
|
boolean twoUBlank = (cell.r - 2 >= 0)
|
||||||
|
&& board.getTile(cell.r - 2, cell.c) == TileColor.NONE;
|
||||||
|
boolean twoUColor = (cell.r - 2 >= 0)
|
||||||
|
&& board.getTile(cell.r - 2, cell.c) == color;
|
||||||
|
|
||||||
|
boolean oneDBlank = (cell.r + 1 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r + 1, cell.c) == TileColor.NONE;
|
||||||
|
boolean oneDColor = (cell.r + 1 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r + 1, cell.c) == color;
|
||||||
|
boolean twoDBlank = (cell.r + 2 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r + 2, cell.c) == TileColor.NONE;
|
||||||
|
boolean twoDColor = (cell.r + 2 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r + 2, cell.c) == color;
|
||||||
|
|
||||||
|
boolean oneLBlank = (cell.c - 1 >= 0)
|
||||||
|
&& board.getTile(cell.r, cell.c - 1) == TileColor.NONE;
|
||||||
|
boolean oneLColor = (cell.c - 1 >= 0)
|
||||||
|
&& board.getTile(cell.r, cell.c - 1) == color;
|
||||||
|
boolean twoLBlank = (cell.c - 2 >= 0)
|
||||||
|
&& board.getTile(cell.r, cell.c - 2) == TileColor.NONE;
|
||||||
|
boolean twoLColor = (cell.c - 2 >= 0)
|
||||||
|
&& board.getTile(cell.r, cell.c - 2) == color;
|
||||||
|
|
||||||
|
boolean oneRBlank = (cell.c + 1 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r, cell.c + 1) == TileColor.NONE;
|
||||||
|
boolean oneRColor = (cell.c + 1 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r, cell.c + 1) == color;
|
||||||
|
boolean twoRBlank = (cell.c + 2 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r, cell.c + 2) == TileColor.NONE;
|
||||||
|
boolean twoRColor = (cell.c + 2 < Board.NUM_ROWS)
|
||||||
|
&& board.getTile(cell.r, cell.c + 2) == color;
|
||||||
|
|
||||||
|
causes = (oneUBlank && twoUColor) || (oneDBlank && twoDColor)
|
||||||
|
|| (oneLBlank && twoLColor) || (oneRBlank && twoRColor)
|
||||||
|
|| (oneDColor && (oneUBlank || twoDBlank))
|
||||||
|
|| (oneUColor && (oneDBlank || twoUBlank))
|
||||||
|
|| (oneLColor && (oneRBlank || twoLBlank))
|
||||||
|
|| (oneRColor && (oneLBlank || twoRBlank));
|
||||||
|
|
||||||
|
return causes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean updateRemovals(Board board, Move m,
|
||||||
|
boolean[][] canBeRemoved) {
|
||||||
|
ArrayList<CellPointer> remove = new ArrayList<CellPointer>();
|
||||||
|
ArrayList<CellPointer> hold;
|
||||||
|
CellPointer cp = m.getCell();
|
||||||
|
TileColor tile = m.getColor();
|
||||||
|
int count;
|
||||||
|
|
||||||
|
// Check up-and-down.
|
||||||
|
count = 1;
|
||||||
|
hold = new ArrayList<CellPointer>();
|
||||||
|
loop: for (int row = cp.r - 1; row >= 0; row--) {
|
||||||
|
if (board.getTile(row, cp.c) == tile) {
|
||||||
|
hold.add(new CellPointer(row, cp.c));
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop: for (int row = cp.r + 1; row < Board.NUM_ROWS; row++) {
|
||||||
|
if (board.getTile(row, cp.c) == tile) {
|
||||||
|
hold.add(new CellPointer(row, cp.c));
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= Board.ROW_REMOVAL_SIZE) {
|
||||||
|
remove.addAll(hold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check left-and-right.
|
||||||
|
count = 1;
|
||||||
|
hold = new ArrayList<CellPointer>();
|
||||||
|
loop: for (int col = cp.c - 1; col >= 0; col--) {
|
||||||
|
if (board.getTile(cp.r, col) == tile) {
|
||||||
|
hold.add(new CellPointer(cp.r, col));
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop: for (int col = cp.c + 1; col < Board.NUM_COLS; col++) {
|
||||||
|
if (board.getTile(cp.r, col) == tile) {
|
||||||
|
hold.add(new CellPointer(cp.r, col));
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= Board.ROW_REMOVAL_SIZE) {
|
||||||
|
remove.addAll(hold);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CellPointer c : remove) {
|
||||||
|
canBeRemoved[c.r][c.c] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
canBeRemoved[cp.r][cp.c] = false;
|
||||||
|
|
||||||
|
return (remove.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameGoal goal = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void denyMove() {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Move getMove(Board board, PlayerModel player) {
|
||||||
|
int remainingPlays = goal.getTargetScore() - board.getTurn();
|
||||||
|
int prediction = board.getEmptySpaces();
|
||||||
|
|
||||||
|
ArrayList<Move> moves = getLegalMoves(board);
|
||||||
|
Object[] movesHolder;
|
||||||
|
|
||||||
|
boolean[][] canBeRemoved = new boolean[Board.NUM_ROWS][Board.NUM_COLS];
|
||||||
|
int[][] blockScore = new int[Board.NUM_ROWS][Board.NUM_COLS];
|
||||||
|
|
||||||
|
for (int r = 0; r < canBeRemoved.length; r++) {
|
||||||
|
for (int c = 0; c < canBeRemoved[0].length; c++) {
|
||||||
|
canBeRemoved[r][c] = false;
|
||||||
|
blockScore[r][c] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
movesHolder = moves.toArray();
|
||||||
|
Move m;
|
||||||
|
for (Object o : movesHolder) {
|
||||||
|
m = (Move) o;
|
||||||
|
if (updateRemovals(board, m, canBeRemoved)) {
|
||||||
|
// blockScore[m.getCell().r][m.getCell().c] +=
|
||||||
|
// !causesConnection(
|
||||||
|
// board, m) ? 2 : 1;
|
||||||
|
blockScore[m.getCell().r][m.getCell().c] += 2;
|
||||||
|
moves.remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (causesConnection(board, m)
|
||||||
|
&& (remainingPlays <= prediction)) {
|
||||||
|
moves.remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (causesConnection(board, m)) {
|
||||||
|
blockScore[m.getCell().r][m.getCell().c]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else if (!causesConnection(board, m)) {
|
||||||
|
// blockScore[m.getCell().r][m.getCell().c]++;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int r = 0; r < canBeRemoved.length; r++) {
|
||||||
|
for (int c = 0; c < canBeRemoved[0].length; c++) {
|
||||||
|
prediction += (canBeRemoved[r][c]) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay. So now...
|
||||||
|
// We have a number of plays we WANT to go to and a number of plays we
|
||||||
|
// EXPECT to go to. If we want to go to a greater number than we expect
|
||||||
|
// to, then we should pick a crap move. If we want to go to a smaller or
|
||||||
|
// equal number, we should block.
|
||||||
|
|
||||||
|
if (moves.size() == 0) {
|
||||||
|
moves = getLegalMoves(board);
|
||||||
|
return moves.get(PlayerModel.rand.nextInt(moves.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (remainingPlays > prediction) {
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
ArrayList<Move> choices = new ArrayList<Move>();
|
||||||
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (blockScore[r][c] == i) {
|
||||||
|
for (Move mv : moves) {
|
||||||
|
if (mv.getCell().r == r && mv.getCell().c == c) {
|
||||||
|
choices.add(mv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choices.size() > 0) {
|
||||||
|
return choices
|
||||||
|
.get(PlayerModel.rand.nextInt(choices.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
int bestScore;
|
||||||
|
while (true) {
|
||||||
|
bestScore = 0;
|
||||||
|
ArrayList<Move> choices = new ArrayList<Move>();
|
||||||
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (blockScore[r][c] > bestScore) {
|
||||||
|
bestScore = blockScore[r][c];
|
||||||
|
choices = new ArrayList<Move>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockScore[r][c] == bestScore) {
|
||||||
|
movesHolder = moves.toArray();
|
||||||
|
|
||||||
|
for (Object o : movesHolder) {
|
||||||
|
m = (Move) o;
|
||||||
|
if (m.getCell().r == r && m.getCell().c == c) {
|
||||||
|
choices.add(m);
|
||||||
|
moves.remove(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choices.size() > 0) {
|
||||||
|
return choices
|
||||||
|
.get(PlayerModel.rand.nextInt(choices.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (blockScore[r][c] == bestScore) {
|
||||||
|
blockScore[r][c] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
goal = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Counting ComPlayer";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Move> getLegalMoves(Board board) {
|
||||||
|
ArrayList<Move> moves = new ArrayList<Move>();
|
||||||
|
|
||||||
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (Board.isLegal(board, new CellPointer(r, c))) {
|
||||||
|
moves.add(new Move(TileColor.BLUE, r, c));
|
||||||
|
moves.add(new Move(TileColor.GREEN, r, c));
|
||||||
|
moves.add(new Move(TileColor.RED, r, c));
|
||||||
|
moves.add(new Move(TileColor.YELLOW, r, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return moves;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import model.Board;
|
|||||||
import model.Board.TileColor;
|
import model.Board.TileColor;
|
||||||
import model.CellPointer;
|
import model.CellPointer;
|
||||||
import model.Move;
|
import model.Move;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class HumanPlayer implements Player {
|
public class HumanPlayer implements Player {
|
||||||
@@ -79,4 +80,9 @@ public class HumanPlayer implements Player {
|
|||||||
public void setColor(TileColor clr) {
|
public void setColor(TileColor clr) {
|
||||||
color = clr;
|
color = clr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import model.Board;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.comPlayer.generator.MinimaxMoveGenerator;
|
import model.comPlayer.generator.MinimaxMoveGenerator;
|
||||||
import model.comPlayer.generator.MoveGenerator;
|
import model.comPlayer.generator.MoveGenerator;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class MinimaxComPlayer implements Player {
|
public class MinimaxComPlayer implements Player {
|
||||||
@@ -28,6 +29,12 @@ public class MinimaxComPlayer implements Player {
|
|||||||
return true; // always ready to play a random valid move
|
return true; // always ready to play a random valid move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Minimax ComPlayer";
|
return "Minimax ComPlayer";
|
||||||
|
|||||||
@@ -4,26 +4,33 @@ import model.Board;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.comPlayer.generator.MonteCarloMoveGenerator;
|
import model.comPlayer.generator.MonteCarloMoveGenerator;
|
||||||
import model.comPlayer.generator.MoveGenerator;
|
import model.comPlayer.generator.MoveGenerator;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class MonteCarloComPlayer implements Player {
|
public class MonteCarloComPlayer implements Player {
|
||||||
private MoveGenerator moveGenerator = new MonteCarloMoveGenerator();
|
private final MoveGenerator moveGenerator = new MonteCarloMoveGenerator();
|
||||||
|
|
||||||
@Override
|
|
||||||
public Move getMove(Board board, PlayerModel playerModel) {
|
|
||||||
return moveGenerator.genMove(board, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void denyMove() {
|
public void denyMove() {
|
||||||
throw new UnsupportedOperationException("Not implemented");
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Move getMove(Board board, PlayerModel playerModel) {
|
||||||
|
return moveGenerator.genMove(board, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return true; // always ready to play a random valid move
|
return true; // always ready to play a random valid move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Monte Carlo ComPlayer";
|
return "Monte Carlo ComPlayer";
|
||||||
|
|||||||
@@ -1,25 +1,14 @@
|
|||||||
package model.comPlayer;
|
package model.comPlayer;
|
||||||
|
|
||||||
import model.Board;
|
import model.Board;
|
||||||
import model.Board.TileColor;
|
|
||||||
import model.Move;
|
import model.Move;
|
||||||
import model.Referee;
|
import model.comPlayer.generator.NeuralNetworkMoveGenerator;
|
||||||
import model.playerModel.Node;
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class NeuralNetworkPlayer implements Player {
|
public class NeuralNetworkPlayer implements Player {
|
||||||
|
|
||||||
public static int getSmallest(double[] list) {
|
private NeuralNetworkMoveGenerator nnGen = null;
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < list.length; i++) {
|
|
||||||
if (list[index] < list[i]) {
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void denyMove() {
|
public void denyMove() {
|
||||||
@@ -28,55 +17,11 @@ public class NeuralNetworkPlayer implements Player {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Move getMove(Board board, PlayerModel player) {
|
public Move getMove(Board board, PlayerModel player) {
|
||||||
Move mv = null;
|
if (nnGen == null) {
|
||||||
|
nnGen = new NeuralNetworkMoveGenerator(player);
|
||||||
Node[] nodes = player.getOutputNodes(Referee.getBoardState(board));
|
|
||||||
|
|
||||||
TileColor color = TileColor.BLUE;
|
|
||||||
|
|
||||||
double[] colorStrengths = new double[4];
|
|
||||||
colorStrengths[0] = nodes[0].strength();
|
|
||||||
colorStrengths[1] = nodes[1].strength();
|
|
||||||
colorStrengths[2] = nodes[2].strength();
|
|
||||||
colorStrengths[3] = nodes[3].strength();
|
|
||||||
|
|
||||||
switch (getSmallest(colorStrengths)) {
|
|
||||||
case 1:
|
|
||||||
color = TileColor.GREEN;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
color = TileColor.RED;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
color = TileColor.YELLOW;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
color = TileColor.BLUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 4;
|
return nnGen.genMove(board, false);
|
||||||
for (int i = 4; i < nodes.length; i++) {
|
|
||||||
if (nodes[i].strength() > nodes[index].strength()) {
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 4;
|
|
||||||
loop: for (int r = 0; r < Board.NUM_ROWS; r++) {
|
|
||||||
for (int c = 0; c < Board.NUM_COLS; c++) {
|
|
||||||
if (i == index) {
|
|
||||||
mv = new Move(color, r, c);
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,6 +29,11 @@ public class NeuralNetworkPlayer implements Player {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Neural Network Player";
|
return "Neural Network Player";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package model.comPlayer;
|
|||||||
|
|
||||||
import model.Board;
|
import model.Board;
|
||||||
import model.Move;
|
import model.Move;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public interface Player {
|
public interface Player {
|
||||||
@@ -26,4 +27,6 @@ public interface Player {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean isReady();
|
public boolean isReady();
|
||||||
|
|
||||||
|
public void setGameGoal(GameGoal target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import model.Board;
|
|||||||
import model.Board.TileColor;
|
import model.Board.TileColor;
|
||||||
import model.CellPointer;
|
import model.CellPointer;
|
||||||
import model.Move;
|
import model.Move;
|
||||||
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class RandomComPlayer implements Player {
|
public class RandomComPlayer implements Player {
|
||||||
@@ -51,6 +52,11 @@ public class RandomComPlayer implements Player {
|
|||||||
return true; // always ready to play a random valid move
|
return true; // always ready to play a random valid move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setGameGoal(GameGoal target) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Random ComPlayer";
|
return "Random ComPlayer";
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import model.SearchResult;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
public class AlphaBetaMoveGenerator implements MoveGenerator {
|
public class AlphaBetaMoveGenerator implements MoveGenerator {
|
||||||
|
private static final int DEFAULT_RECURSIVE_PLAYS = 1;
|
||||||
private static final Logger LOGGER = Logger
|
private static final Logger LOGGER = Logger
|
||||||
.getLogger(AlphaBetaMoveGenerator.class.getName());
|
.getLogger(AlphaBetaMoveGenerator.class.getName());
|
||||||
private static final int DEFAULT_RECURSIVE_PLAYS = 2;
|
|
||||||
|
|
||||||
private final BoardScorer scorer = new BoardScorer();
|
private final BoardScorer scorer = new BoardScorer();
|
||||||
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
||||||
@@ -22,16 +22,26 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
public Move genMove(Board board, boolean asHuman) {
|
public Move genMove(Board board, boolean asHuman) {
|
||||||
|
|
||||||
if (!asHuman) {
|
if (!asHuman) {
|
||||||
return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, Integer.MIN_VALUE,
|
return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2,
|
||||||
Integer.MAX_VALUE).move;
|
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
||||||
} else {
|
} else {
|
||||||
return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, Integer.MIN_VALUE,
|
return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2,
|
||||||
Integer.MAX_VALUE).move;
|
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchResult getMaxValue(Board board, boolean asHuman, int recursionLevel,
|
/**
|
||||||
int alpha, int beta) {
|
* AlphaBetaMoveGenerator2 does not support this method.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
||||||
|
Move[] doNothing = new Move[] { Move.NONE };
|
||||||
|
LOGGER.info("Minimax genMoves() stub returning []");
|
||||||
|
return Arrays.asList(doNothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchResult getMaxValue(Board board, boolean asHuman,
|
||||||
|
int recursionLevel, int alpha, int beta) {
|
||||||
if (recursionLevel < 1) {
|
if (recursionLevel < 1) {
|
||||||
return new SearchResult(Move.NONE, scorer.getScore(board));
|
return new SearchResult(Move.NONE, scorer.getScore(board));
|
||||||
}
|
}
|
||||||
@@ -53,8 +63,8 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
"Illegal move attempted during search!");
|
"Illegal move attempted during search!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResult searchResult = new SearchResult(nextMove,getMinValue(nextBoard, !asHuman, recursionLevel - 1,
|
SearchResult searchResult = new SearchResult(nextMove, getMinValue(
|
||||||
alpha, beta).score);
|
nextBoard, !asHuman, recursionLevel - 1, alpha, beta).score);
|
||||||
|
|
||||||
if (searchResult.compareTo(bestResult) > 0) {
|
if (searchResult.compareTo(bestResult) > 0) {
|
||||||
bestResult = searchResult;
|
bestResult = searchResult;
|
||||||
@@ -70,8 +80,8 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
return bestResult;
|
return bestResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchResult getMinValue(Board board, boolean asHuman, int recursionLevel,
|
private SearchResult getMinValue(Board board, boolean asHuman,
|
||||||
int alpha, int beta) {
|
int recursionLevel, int alpha, int beta) {
|
||||||
if (recursionLevel < 1) {
|
if (recursionLevel < 1) {
|
||||||
return new SearchResult(Move.NONE, scorer.getScore(board));
|
return new SearchResult(Move.NONE, scorer.getScore(board));
|
||||||
}
|
}
|
||||||
@@ -93,8 +103,8 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
"Illegal move attempted during search!");
|
"Illegal move attempted during search!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResult searchResult = new SearchResult(nextMove,getMaxValue(nextBoard, !asHuman, recursionLevel - 1,
|
SearchResult searchResult = new SearchResult(nextMove, getMaxValue(
|
||||||
alpha, beta).score);
|
nextBoard, !asHuman, recursionLevel - 1, alpha, beta).score);
|
||||||
|
|
||||||
if (searchResult.compareTo(bestResult) < 0) {
|
if (searchResult.compareTo(bestResult) < 0) {
|
||||||
bestResult = searchResult;
|
bestResult = searchResult;
|
||||||
@@ -109,14 +119,4 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
|
|
||||||
return bestResult;
|
return bestResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* AlphaBetaMoveGenerator2 does not support this method.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
|
||||||
Move[] doNothing = new Move[] { Move.NONE };
|
|
||||||
LOGGER.info("Minimax genMoves() stub returning []");
|
|
||||||
return Arrays.asList(doNothing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package model.comPlayer.generator;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import model.Board;
|
||||||
|
import model.Board.TileColor;
|
||||||
|
import model.CellPointer;
|
||||||
|
import model.Move;
|
||||||
|
import model.Referee;
|
||||||
|
import model.playerModel.Node;
|
||||||
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
|
public class NeuralNetworkMoveGenerator implements MoveGenerator {
|
||||||
|
|
||||||
|
public static int getSmallest(double[] list) {
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
if (list[index] < list[i]) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerModel player;
|
||||||
|
|
||||||
|
public NeuralNetworkMoveGenerator(PlayerModel pm) {
|
||||||
|
player = pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Move genMove(Board board, boolean asHuman) {
|
||||||
|
Move mv = null;
|
||||||
|
|
||||||
|
Node[] nodes = player.getOutputNodes(Referee.getBoardState(board));
|
||||||
|
|
||||||
|
TileColor color = TileColor.BLUE;
|
||||||
|
|
||||||
|
double[] colorStrengths = new double[4];
|
||||||
|
colorStrengths[0] = nodes[0].strength();
|
||||||
|
colorStrengths[1] = nodes[1].strength();
|
||||||
|
colorStrengths[2] = nodes[2].strength();
|
||||||
|
colorStrengths[3] = nodes[3].strength();
|
||||||
|
|
||||||
|
switch (getSmallest(colorStrengths)) {
|
||||||
|
case 1:
|
||||||
|
color = TileColor.GREEN;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
color = TileColor.RED;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
color = TileColor.YELLOW;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
color = TileColor.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 4;
|
||||||
|
for (int i = 4; i < nodes.length; i++) {
|
||||||
|
if (nodes[i].strength() > nodes[index].strength()) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 4;
|
||||||
|
loop: for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
|
if (i == index) {
|
||||||
|
mv = new Move(color, r, c);
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!Board.isLegal(board, mv.getCell())) {
|
||||||
|
mv = new Move(mv.getColor(), new CellPointer(
|
||||||
|
PlayerModel.rand.nextInt(Board.NUM_ROWS),
|
||||||
|
PlayerModel.rand.nextInt(Board.NUM_COLS)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
||||||
|
// Do nothing.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import model.Board;
|
import model.Board;
|
||||||
import model.Board.TileColor;
|
import model.Board.TileColor;
|
||||||
|
import model.CellPointer;
|
||||||
import model.Move;
|
import model.Move;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
@@ -25,14 +26,14 @@ public class ValidMoveGenerator implements MoveGenerator {
|
|||||||
|
|
||||||
List<Move> validMoves = new ArrayList<Move>();
|
List<Move> validMoves = new ArrayList<Move>();
|
||||||
|
|
||||||
for (int i = 0; i < Board.NUM_ROWS; i++) {
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
for (int j = 0; j < Board.NUM_COLS; j++) {
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
if (board.getTile(i, j) == TileColor.NONE) {
|
if (Board.isLegal(board, new CellPointer(r, c))) {
|
||||||
for (TileColor color : TileColor.values()) {
|
for (TileColor color : TileColor.values()) {
|
||||||
if (color == TileColor.NONE) {
|
if (color == TileColor.NONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
validMoves.add(new Move(color, i, j));
|
validMoves.add(new Move(color, r, c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,12 +134,23 @@ public class PlayerModel implements Serializable {
|
|||||||
|
|
||||||
public Node[] getOutputNodes(boolean[] input) {
|
public Node[] getOutputNodes(boolean[] input) {
|
||||||
if (input.length == inputNode.length) {
|
if (input.length == inputNode.length) {
|
||||||
|
for (int i = 0; i < input.length; i++) {
|
||||||
|
inputNode[i].setStimulation(input[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return outputNode;
|
return outputNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<GameLog> getScores() {
|
||||||
|
GameLog.SORT_BY_SCORE = false;
|
||||||
|
Collections.sort(scores);
|
||||||
|
|
||||||
|
return scores;
|
||||||
|
}
|
||||||
|
|
||||||
public GameGoal getTargetScore() {
|
public GameGoal getTargetScore() {
|
||||||
GameGoal goal;
|
GameGoal goal;
|
||||||
int targetScore;
|
int targetScore;
|
||||||
@@ -203,12 +214,13 @@ public class PlayerModel implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void train(boolean[] boardState, boolean[] example) {
|
public void train(boolean[] example) {
|
||||||
getOutputNodes(boardState);
|
boolean[] hold = getOutputActivations();
|
||||||
|
|
||||||
|
// System.out.println("TRAIN");
|
||||||
if (example.length == outputNode.length) {
|
if (example.length == outputNode.length) {
|
||||||
for (int i = 0; i < outputNode.length; i++) {
|
for (int i = 0; i < outputNode.length; i++) {
|
||||||
outputNode[i].learn(example[i]);
|
outputNode[i].learn(example[i] == hold[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,4 +228,14 @@ public class PlayerModel implements Serializable {
|
|||||||
private int getHighScore() {
|
private int getHighScore() {
|
||||||
return getHighScores()[0];
|
return getHighScores()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean[] getOutputActivations() {
|
||||||
|
boolean[] acts = new boolean[outputNode.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < acts.length; i++) {
|
||||||
|
acts[i] = outputNode[i].axon();
|
||||||
|
}
|
||||||
|
|
||||||
|
return acts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class SigmoidNode implements Node {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
// Training rate.
|
// Training rate.
|
||||||
private final double A = .15;
|
private final double A = .05;
|
||||||
|
|
||||||
private final Hashtable<Node, Double> dendrites = new Hashtable<Node, Double>();
|
private final Hashtable<Node, Double> dendrites = new Hashtable<Node, Double>();
|
||||||
|
|
||||||
@@ -36,6 +36,8 @@ public class SigmoidNode implements Node {
|
|||||||
n.learn(correct);
|
n.learn(correct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System.out.println(strength());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,18 +2,24 @@ package view;
|
|||||||
|
|
||||||
import model.comPlayer.AdaptiveComPlayer;
|
import model.comPlayer.AdaptiveComPlayer;
|
||||||
import model.comPlayer.AlphaBetaComPlayer;
|
import model.comPlayer.AlphaBetaComPlayer;
|
||||||
|
import model.comPlayer.ComboPlayer;
|
||||||
|
import model.comPlayer.CountingPlayer;
|
||||||
import model.comPlayer.MinimaxComPlayer;
|
import model.comPlayer.MinimaxComPlayer;
|
||||||
import model.comPlayer.MonteCarloComPlayer;
|
import model.comPlayer.MonteCarloComPlayer;
|
||||||
|
import model.comPlayer.NeuralNetworkPlayer;
|
||||||
import model.comPlayer.Player;
|
import model.comPlayer.Player;
|
||||||
import model.comPlayer.RandomComPlayer;
|
import model.comPlayer.RandomComPlayer;
|
||||||
|
|
||||||
public class ParsedArgs {
|
public class ParsedArgs {
|
||||||
public static final String COM_ADAPTIVE = "ADAPTIVE";
|
public static final String COM_ADAPTIVE = "ADAPTIVE";
|
||||||
public static final String COM_ALPHABETA = "ALPHABETA";
|
public static final String COM_ALPHABETA = "ALPHABETA";
|
||||||
|
public static final String COM_ANN = "NEURALNET";
|
||||||
|
public static final String COM_COMBO = "COMBO";
|
||||||
|
public static final String COM_COUNTING = "COUNTING";
|
||||||
|
public static final String COM_DEFAULT = COM_ALPHABETA;
|
||||||
public static final String COM_MINIMAX = "MINIMAX";
|
public static final String COM_MINIMAX = "MINIMAX";
|
||||||
public static final String COM_MONTECARLO = "MONTECARLO";
|
public static final String COM_MONTECARLO = "MONTECARLO";
|
||||||
public static final String COM_RANDOM = "RANDOM";
|
public static final String COM_RANDOM = "RANDOM";
|
||||||
public static final String COM_DEFAULT = COM_ALPHABETA;
|
|
||||||
|
|
||||||
private String comPlayer = COM_DEFAULT;
|
private String comPlayer = COM_DEFAULT;
|
||||||
|
|
||||||
@@ -28,8 +34,15 @@ public class ParsedArgs {
|
|||||||
return new AlphaBetaComPlayer();
|
return new AlphaBetaComPlayer();
|
||||||
} else if (COM_MONTECARLO.equalsIgnoreCase(comPlayer)) {
|
} else if (COM_MONTECARLO.equalsIgnoreCase(comPlayer)) {
|
||||||
return new MonteCarloComPlayer();
|
return new MonteCarloComPlayer();
|
||||||
|
} else if (COM_ANN.equalsIgnoreCase(comPlayer)) {
|
||||||
|
return new NeuralNetworkPlayer();
|
||||||
|
} else if (COM_COMBO.equalsIgnoreCase(comPlayer)) {
|
||||||
|
return new ComboPlayer();
|
||||||
|
} else if (COM_COUNTING.equalsIgnoreCase(comPlayer)) {
|
||||||
|
return new CountingPlayer();
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Unrecognized comPlayer '" + comPlayer +"', using default: " + COM_DEFAULT);
|
System.out.println("Unrecognized comPlayer '" + comPlayer
|
||||||
|
+ "', using default: " + COM_DEFAULT);
|
||||||
return new AlphaBetaComPlayer();
|
return new AlphaBetaComPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
test/model/DumpResults.java
Normal file
35
test/model/DumpResults.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package model;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
|
||||||
|
import model.playerModel.GameLog;
|
||||||
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
|
public class DumpResults {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
FileInputStream fin = null;
|
||||||
|
ObjectInputStream oin = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fin = new FileInputStream(PlayerModel.getPlayerPath("marshall"));
|
||||||
|
|
||||||
|
oin = new ObjectInputStream(fin);
|
||||||
|
PlayerModel pm = (PlayerModel) oin.readObject();
|
||||||
|
oin.close();
|
||||||
|
|
||||||
|
for (GameLog gl : pm.getScores()) {
|
||||||
|
System.out.println(gl.getScore());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user