- Created a new ComPlayer. It targets a particular score, and does it pretty well. It does this by counting the number of empty spaces and the number of empty spaces that can potentially be created by removing tiles then either playing to block or playing to extend the game.

- Created DumpResults.java, which simply outputs all scores in a player model so that they can be graphed.
This commit is contained in:
Marshall
2012-04-30 05:18:02 -04:00
parent 8de42a3562
commit 0724d44ec4
7 changed files with 364 additions and 2 deletions

View File

@@ -117,6 +117,19 @@ public class Board {
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) {
return board[r][c];
}

View File

@@ -3,6 +3,7 @@ package model;
import model.Board.TileColor;
import model.comPlayer.HumanPlayer;
import model.comPlayer.Player;
import model.playerModel.GameGoal;
import model.playerModel.PlayerModel;
import org.apache.log4j.Logger;
@@ -102,6 +103,9 @@ public class Referee implements Runnable {
while (true) {
initGame();
mf.updateBoard();
GameGoal goal = playerModel.getTargetScore();
System.out.println("Target: " + goal.getTargetScore());
computerPlayer.setGameGoal(goal);
play();
getPlayerModel().logGame(getPlayerScore());

View 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;
}
}

View File

@@ -144,6 +144,13 @@ public class PlayerModel implements Serializable {
return null;
}
public ArrayList<GameLog> getScores() {
GameLog.SORT_BY_SCORE = false;
Collections.sort(scores);
return scores;
}
public GameGoal getTargetScore() {
GameGoal goal;
int targetScore;
@@ -210,7 +217,7 @@ public class PlayerModel implements Serializable {
public void train(boolean[] example) {
boolean[] hold = getOutputActivations();
System.out.println("TRAIN");
// System.out.println("TRAIN");
if (example.length == outputNode.length) {
for (int i = 0; i < outputNode.length; i++) {
outputNode[i].learn(example[i] == hold[i]);

View File

@@ -37,7 +37,7 @@ public class SigmoidNode implements Node {
}
}
System.out.println(strength());
// System.out.println(strength());
}
@Override