diff --git a/src/model/Referee.java b/src/model/Referee.java index 55d4748..e192ef7 100644 --- a/src/model/Referee.java +++ b/src/model/Referee.java @@ -128,7 +128,8 @@ public class Referee implements Runnable { int tile = 0; for (int r = 0; r < Board.NUM_ROWS; r++) { 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 +164,13 @@ public class Referee implements Runnable { System.out .println("Interrupted while waiting for human to move!"); } else { + getPlayerModel().getOutputNodes(getBoardState(board)); + Move mv = humanPlayer.getMove(board, playerModel); if (board.getTile(mv.getCell().r, mv.getCell().c) == TileColor.NONE) { playToken(humanPlayer.getMove(board, playerModel)); - getPlayerModel().train(getBoardState(board), - getMoveArray(mv)); + getPlayerModel().train(getMoveArray(mv)); } else { humanPlayer.denyMove(); @@ -177,7 +179,7 @@ public class Referee implements Runnable { } else { Move mv = computerPlayer.getMove(board, getPlayerModel()); playToken(mv); - + // This is the call that gets a prediction of a user's move. // Some changes will probably be necessary to put it in the // right place and also to get the node weights. But... all in diff --git a/src/model/comPlayer/AlphaBetaComPlayer.java b/src/model/comPlayer/AlphaBetaComPlayer.java index aee56f7..0e965de 100644 --- a/src/model/comPlayer/AlphaBetaComPlayer.java +++ b/src/model/comPlayer/AlphaBetaComPlayer.java @@ -4,6 +4,7 @@ import model.Board; import model.Move; import model.comPlayer.generator.AlphaBetaMoveGenerator; import model.comPlayer.generator.MoveGenerator; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class AlphaBetaComPlayer implements Player { @@ -24,6 +25,12 @@ public class AlphaBetaComPlayer implements Player { return true; // always ready to play a random valid move } + @Override + public void setGameGoal(GameGoal target) { + // TODO Auto-generated method stub + + } + @Override public String toString() { return "Alpha-Beta ComPlayer"; diff --git a/src/model/comPlayer/ComboPlayer.java b/src/model/comPlayer/ComboPlayer.java new file mode 100644 index 0000000..c141d84 --- /dev/null +++ b/src/model/comPlayer/ComboPlayer.java @@ -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. + } +} diff --git a/src/model/comPlayer/HumanPlayer.java b/src/model/comPlayer/HumanPlayer.java index f86c472..18e8840 100644 --- a/src/model/comPlayer/HumanPlayer.java +++ b/src/model/comPlayer/HumanPlayer.java @@ -4,6 +4,7 @@ import model.Board; import model.Board.TileColor; import model.CellPointer; import model.Move; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class HumanPlayer implements Player { @@ -79,4 +80,9 @@ public class HumanPlayer implements Player { public void setColor(TileColor clr) { color = clr; } + + @Override + public void setGameGoal(GameGoal target) { + // Do nothing. + } } \ No newline at end of file diff --git a/src/model/comPlayer/MinimaxComPlayer.java b/src/model/comPlayer/MinimaxComPlayer.java index 81c6fdc..6189a6d 100644 --- a/src/model/comPlayer/MinimaxComPlayer.java +++ b/src/model/comPlayer/MinimaxComPlayer.java @@ -4,6 +4,7 @@ import model.Board; import model.Move; import model.comPlayer.generator.MinimaxMoveGenerator; import model.comPlayer.generator.MoveGenerator; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class MinimaxComPlayer implements Player { @@ -28,6 +29,12 @@ public class MinimaxComPlayer implements Player { return true; // always ready to play a random valid move } + @Override + public void setGameGoal(GameGoal target) { + // TODO Auto-generated method stub + + } + @Override public String toString() { return "Minimax ComPlayer"; diff --git a/src/model/comPlayer/MonteCarloComPlayer.java b/src/model/comPlayer/MonteCarloComPlayer.java index fca3b52..2b78c73 100644 --- a/src/model/comPlayer/MonteCarloComPlayer.java +++ b/src/model/comPlayer/MonteCarloComPlayer.java @@ -4,26 +4,33 @@ import model.Board; import model.Move; import model.comPlayer.generator.MonteCarloMoveGenerator; import model.comPlayer.generator.MoveGenerator; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class MonteCarloComPlayer implements Player { - private MoveGenerator moveGenerator = new MonteCarloMoveGenerator(); - - @Override - public Move getMove(Board board, PlayerModel playerModel) { - return moveGenerator.genMove(board, false); - } + private final MoveGenerator moveGenerator = new MonteCarloMoveGenerator(); @Override public void denyMove() { throw new UnsupportedOperationException("Not implemented"); } + @Override + public Move getMove(Board board, PlayerModel playerModel) { + return moveGenerator.genMove(board, false); + } + @Override public boolean isReady() { return true; // always ready to play a random valid move } + @Override + public void setGameGoal(GameGoal target) { + // TODO Auto-generated method stub + + } + @Override public String toString() { return "Monte Carlo ComPlayer"; diff --git a/src/model/comPlayer/NeuralNetworkPlayer.java b/src/model/comPlayer/NeuralNetworkPlayer.java index 78b3a6f..d4c5c71 100644 --- a/src/model/comPlayer/NeuralNetworkPlayer.java +++ b/src/model/comPlayer/NeuralNetworkPlayer.java @@ -1,25 +1,14 @@ package model.comPlayer; import model.Board; -import model.Board.TileColor; import model.Move; -import model.Referee; -import model.playerModel.Node; +import model.comPlayer.generator.NeuralNetworkMoveGenerator; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class NeuralNetworkPlayer implements Player { - 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; - } + private NeuralNetworkMoveGenerator nnGen = null; @Override public void denyMove() { @@ -28,55 +17,11 @@ public class NeuralNetworkPlayer implements Player { @Override public Move getMove(Board board, PlayerModel player) { - 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; + if (nnGen == null) { + nnGen = new NeuralNetworkMoveGenerator(player); } - 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++; - } - } - } - - return mv; + return nnGen.genMove(board, false); } @Override @@ -84,6 +29,11 @@ public class NeuralNetworkPlayer implements Player { return true; } + @Override + public void setGameGoal(GameGoal target) { + // Do nothing. + } + @Override public String toString() { return "Neural Network Player"; diff --git a/src/model/comPlayer/Player.java b/src/model/comPlayer/Player.java index b3c37bb..793c2cc 100644 --- a/src/model/comPlayer/Player.java +++ b/src/model/comPlayer/Player.java @@ -2,6 +2,7 @@ package model.comPlayer; import model.Board; import model.Move; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public interface Player { @@ -26,4 +27,6 @@ public interface Player { * @return */ public boolean isReady(); + + public void setGameGoal(GameGoal target); } diff --git a/src/model/comPlayer/RandomComPlayer.java b/src/model/comPlayer/RandomComPlayer.java index 4ed1b41..c2cd83c 100644 --- a/src/model/comPlayer/RandomComPlayer.java +++ b/src/model/comPlayer/RandomComPlayer.java @@ -6,6 +6,7 @@ import model.Board; import model.Board.TileColor; import model.CellPointer; import model.Move; +import model.playerModel.GameGoal; import model.playerModel.PlayerModel; public class RandomComPlayer implements Player { @@ -51,6 +52,11 @@ public class RandomComPlayer implements Player { return true; // always ready to play a random valid move } + @Override + public void setGameGoal(GameGoal target) { + // TODO Auto-generated method stub + } + @Override public String toString() { return "Random ComPlayer"; diff --git a/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java b/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java new file mode 100644 index 0000000..1eb59e3 --- /dev/null +++ b/src/model/comPlayer/generator/NeuralNetworkMoveGenerator.java @@ -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 genMoves(Board board, boolean asHuman, int nMoves) { + // Do nothing. + return null; + } + +} \ No newline at end of file diff --git a/src/model/playerModel/PlayerModel.java b/src/model/playerModel/PlayerModel.java index 2570d1d..22240ca 100644 --- a/src/model/playerModel/PlayerModel.java +++ b/src/model/playerModel/PlayerModel.java @@ -134,6 +134,10 @@ public class PlayerModel implements Serializable { public Node[] getOutputNodes(boolean[] input) { if (input.length == inputNode.length) { + for (int i = 0; i < input.length; i++) { + inputNode[i].setStimulation(input[i]); + } + return outputNode; } @@ -203,12 +207,13 @@ public class PlayerModel implements Serializable { } } - public void train(boolean[] boardState, boolean[] example) { - getOutputNodes(boardState); + public void train(boolean[] example) { + boolean[] hold = getOutputActivations(); + System.out.println("TRAIN"); if (example.length == outputNode.length) { for (int i = 0; i < outputNode.length; i++) { - outputNode[i].learn(example[i]); + outputNode[i].learn(example[i] == hold[i]); } } } @@ -216,4 +221,14 @@ public class PlayerModel implements Serializable { private int getHighScore() { 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; + } } diff --git a/src/model/playerModel/node/SigmoidNode.java b/src/model/playerModel/node/SigmoidNode.java index c19c02a..60af9f9 100644 --- a/src/model/playerModel/node/SigmoidNode.java +++ b/src/model/playerModel/node/SigmoidNode.java @@ -9,7 +9,7 @@ public class SigmoidNode implements Node { private static final long serialVersionUID = 1L; // Training rate. - private final double A = .15; + private final double A = .05; private final Hashtable dendrites = new Hashtable(); @@ -36,6 +36,8 @@ public class SigmoidNode implements Node { n.learn(correct); } } + + System.out.println(strength()); } @Override diff --git a/src/view/ParsedArgs.java b/src/view/ParsedArgs.java index 17c547d..e42ed91 100644 --- a/src/view/ParsedArgs.java +++ b/src/view/ParsedArgs.java @@ -1,20 +1,24 @@ package view; import model.comPlayer.AlphaBetaComPlayer; +import model.comPlayer.ComboPlayer; import model.comPlayer.MinimaxComPlayer; import model.comPlayer.MonteCarloComPlayer; +import model.comPlayer.NeuralNetworkPlayer; import model.comPlayer.Player; import model.comPlayer.RandomComPlayer; public class ParsedArgs { - public static final String COM_RANDOM = "RANDOM"; - public static final String COM_MINIMAX = "MINIMAX"; public static final String COM_ALPHABETA = "ALPHABETA"; - public static final String COM_MONTECARLO = "MONTECARLO"; + public static final String COM_ANN = "NEURALNET"; + public static final String COM_COMBO = "COMBO"; public static final String COM_DEFAULT = COM_ALPHABETA; - + public static final String COM_MINIMAX = "MINIMAX"; + public static final String COM_MONTECARLO = "MONTECARLO"; + public static final String COM_RANDOM = "RANDOM"; + private String comPlayer = COM_DEFAULT; - + public Player getComPlayer() { if (COM_RANDOM.equalsIgnoreCase(comPlayer)) { return new RandomComPlayer(); @@ -24,13 +28,18 @@ public class ParsedArgs { return new AlphaBetaComPlayer(); } else if (COM_MONTECARLO.equalsIgnoreCase(comPlayer)) { return new MonteCarloComPlayer(); + } else if (COM_ANN.equalsIgnoreCase(comPlayer)) { + return new NeuralNetworkPlayer(); + } else if (COM_COMBO.equalsIgnoreCase(comPlayer)) { + return new ComboPlayer(); } else { - System.out.println("Unrecognized comPlayer '" + comPlayer +"', using default: " + COM_DEFAULT); + System.out.println("Unrecognized comPlayer '" + comPlayer + + "', using default: " + COM_DEFAULT); return new AlphaBetaComPlayer(); } } - - public void setComPlayer(String comPlayer) { + + public void setComPlayer(String comPlayer) { this.comPlayer = comPlayer; } } \ No newline at end of file