Substantially improved performance of Board.isLegal().

No longer a static method.
AlphaBeta is now playable with 4-move lookahead (although slow).
This commit is contained in:
Woody Folsom
2012-05-01 09:38:32 -04:00
parent 48915071d4
commit 924780baaf
4 changed files with 37 additions and 42 deletions

View File

@@ -12,14 +12,20 @@ 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) { private boolean boardEmpty = true;
public boolean isLegal(CellPointer cp) {
//coordinates are out of board bounds
if (cp.r < 0 || cp.r >= Board.NUM_ROWS || cp.c < 0 if (cp.r < 0 || cp.r >= Board.NUM_ROWS || cp.c < 0
|| cp.c >= Board.NUM_COLS) { || cp.c >= Board.NUM_COLS) {
return false; return false;
} }
boolean legal = (brd.getTile(cp.r, cp.c) == TileColor.NONE); //target coordinate already has a tile
if (board[cp.r][cp.c] != TileColor.NONE) {
return false;
}
boolean rowUp = (cp.r - 1) >= 0; boolean rowUp = (cp.r - 1) >= 0;
boolean rowDown = (cp.r + 1) < Board.NUM_ROWS; boolean rowDown = (cp.r + 1) < Board.NUM_ROWS;
boolean colUp = (cp.c - 1) >= 0; boolean colUp = (cp.c - 1) >= 0;
@@ -27,49 +33,49 @@ public class Board {
// r-1 / c-1 // r-1 / c-1
if (rowUp && colUp if (rowUp && colUp
&& (brd.getTile(cp.r - 1, cp.c - 1) != TileColor.NONE)) { && (board[cp.r - 1][ cp.c - 1] != TileColor.NONE)) {
return legal && true; return true;
} }
// r-1 / c // r-1 / c
if (rowUp && (brd.getTile(cp.r - 1, cp.c) != TileColor.NONE)) { if (rowUp && (board[cp.r - 1][ cp.c] != TileColor.NONE)) {
return legal && true; return true;
} }
// r-1 / c+1 // r-1 / c+1
if (rowUp && colDown if (rowUp && colDown
&& (brd.getTile(cp.r - 1, cp.c + 1) != TileColor.NONE)) { && (board[cp.r - 1][ cp.c + 1] != TileColor.NONE)) {
return legal && true; return true;
} }
// r / c-1 // r / c-1
if (colUp && (brd.getTile(cp.r, cp.c - 1) != TileColor.NONE)) { if (colUp && (board[cp.r][ cp.c - 1] != TileColor.NONE)) {
return legal && true; return true;
} }
// r / c+1 // r / c+1
if (colDown && (brd.getTile(cp.r, cp.c + 1) != TileColor.NONE)) { if (colDown && (board[cp.r][ cp.c + 1] != TileColor.NONE)) {
return legal && true; return true;
} }
// r+1 / c-1 // r+1 / c-1
if (rowDown && colUp if (rowDown && colUp
&& (brd.getTile(cp.r + 1, cp.c - 1) != TileColor.NONE)) { && (board[cp.r + 1][ cp.c - 1] != TileColor.NONE)) {
return legal && true; return true;
} }
// r+1 / c // r+1 / c
if (rowDown && (brd.getTile(cp.r + 1, cp.c) != TileColor.NONE)) { if (rowDown && (board[cp.r + 1][ cp.c] != TileColor.NONE)) {
return legal && true; return true;
} }
// r+1 / c+1 // r+1 / c+1
if (rowDown && colDown if (rowDown && colDown
&& (brd.getTile(cp.r + 1, cp.c + 1) != TileColor.NONE)) { && (board[cp.r + 1][ cp.c + 1] != TileColor.NONE)) {
return legal && true; return true;
} }
return brd.isEmpty(); return boardEmpty;
} }
private final TileColor[][] board; private final TileColor[][] board;
@@ -91,6 +97,7 @@ public class Board {
for (int r = 0; r < NUM_ROWS; r++) { for (int r = 0; r < NUM_ROWS; r++) {
for (int c = 0; c < NUM_COLS; c++) { for (int c = 0; c < NUM_COLS; c++) {
this.boardEmpty = that.boardEmpty;
this.board[r][c] = that.board[r][c]; this.board[r][c] = that.board[r][c];
} }
} }
@@ -163,7 +170,7 @@ public class Board {
} }
public boolean playTile(CellPointer cp, TileColor tile) { public boolean playTile(CellPointer cp, TileColor tile) {
if (!isLegal(this, cp)) { if (!isLegal(cp)) {
return false; // Illegal move. return false; // Illegal move.
} }
@@ -304,6 +311,8 @@ public class Board {
} }
numPlies++; numPlies++;
boardEmpty = false;
return true; return true;
} }
@@ -320,16 +329,4 @@ 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;
}
} }

View File

@@ -286,7 +286,7 @@ public class CountingPlayer implements Player {
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++) {
if (Board.isLegal(board, new CellPointer(r, c))) { if (board.isLegal(new CellPointer(r, c))) {
moves.add(new Move(TileColor.BLUE, r, c)); moves.add(new Move(TileColor.BLUE, r, c));
moves.add(new Move(TileColor.GREEN, r, c)); moves.add(new Move(TileColor.GREEN, r, c));
moves.add(new Move(TileColor.RED, r, c)); moves.add(new Move(TileColor.RED, r, c));

View File

@@ -80,7 +80,7 @@ public class NeuralNetworkMoveGenerator implements MoveGenerator {
} }
} }
while (!Board.isLegal(board, mv.getCell())) { while (!board.isLegal(mv.getCell())) {
mv = new Move(mv.getColor(), new CellPointer( mv = new Move(mv.getColor(), new CellPointer(
PlayerModel.rand.nextInt(Board.NUM_ROWS), PlayerModel.rand.nextInt(Board.NUM_ROWS),
PlayerModel.rand.nextInt(Board.NUM_COLS))); PlayerModel.rand.nextInt(Board.NUM_COLS)));

View File

@@ -22,13 +22,11 @@ public class ValidMoveGenerator implements MoveGenerator {
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++) {
if (Board.isLegal(board, new CellPointer(r, c))) { if (board.isLegal(new CellPointer(r, c))) {
for (TileColor color : TileColor.values()) { validMoves.add(new Move(TileColor.BLUE, r, c));
if (color == TileColor.NONE) { validMoves.add(new Move(TileColor.GREEN, r, c));
continue; validMoves.add(new Move(TileColor.RED, r, c));
} validMoves.add(new Move(TileColor.YELLOW, r, c));
validMoves.add(new Move(color, r, c));
}
} }
} }
} }