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:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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));
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user