- Changed the rules. Now tiles can only be placed next to existing tiles. Unless the board is empty.
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.
|
||||||
@@ -62,7 +122,7 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getTurn() {
|
public int getTurn() {
|
||||||
return (numPlies + 1)/ 2;
|
return (numPlies + 1) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,8 +150,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 +307,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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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,24 +22,34 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Move> validMoves = validMoveGenerator.genMoves(board, asHuman,
|
List<Move> validMoves = validMoveGenerator.genMoves(board, asHuman,
|
||||||
MoveGenerator.ALL_MOVES);
|
MoveGenerator.ALL_MOVES);
|
||||||
|
|
||||||
SearchResult bestResult = new SearchResult(Move.NONE,Integer.MIN_VALUE);
|
SearchResult bestResult = new SearchResult(Move.NONE, Integer.MIN_VALUE);
|
||||||
|
|
||||||
if (validMoves.size() == 0) {
|
if (validMoves.size() == 0) {
|
||||||
return bestResult;
|
return bestResult;
|
||||||
@@ -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,16 +80,16 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Move> validMoves = validMoveGenerator.genMoves(board, asHuman,
|
List<Move> validMoves = validMoveGenerator.genMoves(board, asHuman,
|
||||||
MoveGenerator.ALL_MOVES);
|
MoveGenerator.ALL_MOVES);
|
||||||
|
|
||||||
SearchResult bestResult = new SearchResult(Move.NONE,Integer.MAX_VALUE);
|
SearchResult bestResult = new SearchResult(Move.NONE, Integer.MAX_VALUE);
|
||||||
|
|
||||||
if (validMoves.size() == 0) {
|
if (validMoves.size() == 0) {
|
||||||
return bestResult;
|
return bestResult;
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +44,7 @@ public class ValidMoveGenerator implements MoveGenerator {
|
|||||||
if (nMoves == MoveGenerator.ALL_MOVES) {
|
if (nMoves == MoveGenerator.ALL_MOVES) {
|
||||||
return validMoves;
|
return validMoves;
|
||||||
} else {
|
} else {
|
||||||
return validMoves.subList(0, Math.min(validMoves.size(),nMoves));
|
return validMoves.subList(0, Math.min(validMoves.size(), nMoves));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user