From e012f17b33669dec34c8c8c239f6979837d7eb11 Mon Sep 17 00:00:00 2001 From: Marshall Date: Sun, 29 Apr 2012 17:11:11 -0400 Subject: [PATCH] - Changed the rules. Now tiles can only be placed next to existing tiles. Unless the board is empty. --- src/model/Board.java | 78 +++++++- .../generator/AlphaBetaMoveGenerator.java | 172 +++++++++--------- .../generator/ValidMoveGenerator.java | 13 +- 3 files changed, 168 insertions(+), 95 deletions(-) diff --git a/src/model/Board.java b/src/model/Board.java index 3fa08fe..c86c246 100644 --- a/src/model/Board.java +++ b/src/model/Board.java @@ -12,6 +12,66 @@ public class Board { public static final int NUM_ROWS = 5; 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; // a Ply is a play by 1 side. Increments each time setTile() is called. @@ -62,7 +122,7 @@ public class Board { } public int getTurn() { - return (numPlies + 1)/ 2; + return (numPlies + 1) / 2; } @Override @@ -90,8 +150,8 @@ public class Board { } public boolean playTile(CellPointer cp, TileColor tile) { - if (board[cp.r][cp.c] != TileColor.NONE) { - return false; // illegal move + if (!isLegal(this, cp)) { + return false; // Illegal move. } board[cp.r][cp.c] = tile; @@ -247,4 +307,16 @@ public class Board { } 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; + } } \ No newline at end of file diff --git a/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java b/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java index 1eb36db..4034cf5 100644 --- a/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java +++ b/src/model/comPlayer/generator/AlphaBetaMoveGenerator.java @@ -11,104 +11,24 @@ import model.SearchResult; import org.apache.log4j.Logger; public class AlphaBetaMoveGenerator implements MoveGenerator { + private static final int DEFAULT_RECURSIVE_PLAYS = 1; private static final Logger LOGGER = Logger .getLogger(AlphaBetaMoveGenerator.class.getName()); - private static final int DEFAULT_RECURSIVE_PLAYS = 2; private final BoardScorer scorer = new BoardScorer(); private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator(); @Override public Move genMove(Board board, boolean asHuman) { - + if (!asHuman) { - return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, Integer.MIN_VALUE, - Integer.MAX_VALUE).move; + return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, + Integer.MIN_VALUE, Integer.MAX_VALUE).move; } else { - return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, Integer.MIN_VALUE, - Integer.MAX_VALUE).move; + return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2, + Integer.MIN_VALUE, Integer.MAX_VALUE).move; } } - - private SearchResult getMaxValue(Board board, boolean asHuman, int recursionLevel, - int alpha, int beta) { - if (recursionLevel < 1) { - return new SearchResult(Move.NONE,scorer.getScore(board)); - } - - List validMoves = validMoveGenerator.genMoves(board, asHuman, - MoveGenerator.ALL_MOVES); - - SearchResult bestResult = new SearchResult(Move.NONE,Integer.MIN_VALUE); - - if (validMoves.size() == 0) { - return bestResult; - } - - for (Move nextMove : validMoves) { - Board nextBoard = new Board(board); - - if (!nextBoard.playTile(nextMove.getCell(), nextMove.getColor())) { - throw new RuntimeException( - "Illegal move attempted during search!"); - } - - SearchResult searchResult = new SearchResult(nextMove,getMinValue(nextBoard, !asHuman, recursionLevel - 1, - alpha, beta).score); - - if (searchResult.compareTo(bestResult) > 0) { - bestResult = searchResult; - } - - if (bestResult.score >= beta) { - return bestResult; - } - - alpha = Math.max(alpha, bestResult.score); - } - - return bestResult; - } - - private SearchResult getMinValue(Board board, boolean asHuman, int recursionLevel, - int alpha, int beta) { - if (recursionLevel < 1) { - return new SearchResult(Move.NONE,scorer.getScore(board)); - } - - List validMoves = validMoveGenerator.genMoves(board, asHuman, - MoveGenerator.ALL_MOVES); - - SearchResult bestResult = new SearchResult(Move.NONE,Integer.MAX_VALUE); - - if (validMoves.size() == 0) { - return bestResult; - } - - for (Move nextMove : validMoves) { - Board nextBoard = new Board(board); - - if (!nextBoard.playTile(nextMove.getCell(), nextMove.getColor())) { - throw new RuntimeException( - "Illegal move attempted during search!"); - } - - SearchResult searchResult = new SearchResult(nextMove,getMaxValue(nextBoard, !asHuman, recursionLevel - 1, - alpha, beta).score); - - if (searchResult.compareTo(bestResult) < 0) { - bestResult = searchResult; - } - - if (bestResult.score <= alpha) { - return bestResult; - } - - beta = Math.min(beta, bestResult.score); - } - - return bestResult; - } /** * AlphaBetaMoveGenerator2 does not support this method. @@ -119,4 +39,84 @@ public class AlphaBetaMoveGenerator implements MoveGenerator { 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) { + return new SearchResult(Move.NONE, scorer.getScore(board)); + } + + List validMoves = validMoveGenerator.genMoves(board, asHuman, + MoveGenerator.ALL_MOVES); + + SearchResult bestResult = new SearchResult(Move.NONE, Integer.MIN_VALUE); + + if (validMoves.size() == 0) { + return bestResult; + } + + for (Move nextMove : validMoves) { + Board nextBoard = new Board(board); + + if (!nextBoard.playTile(nextMove.getCell(), nextMove.getColor())) { + throw new RuntimeException( + "Illegal move attempted during search!"); + } + + SearchResult searchResult = new SearchResult(nextMove, getMinValue( + nextBoard, !asHuman, recursionLevel - 1, alpha, beta).score); + + if (searchResult.compareTo(bestResult) > 0) { + bestResult = searchResult; + } + + if (bestResult.score >= beta) { + return bestResult; + } + + alpha = Math.max(alpha, bestResult.score); + } + + return bestResult; + } + + private SearchResult getMinValue(Board board, boolean asHuman, + int recursionLevel, int alpha, int beta) { + if (recursionLevel < 1) { + return new SearchResult(Move.NONE, scorer.getScore(board)); + } + + List validMoves = validMoveGenerator.genMoves(board, asHuman, + MoveGenerator.ALL_MOVES); + + SearchResult bestResult = new SearchResult(Move.NONE, Integer.MAX_VALUE); + + if (validMoves.size() == 0) { + return bestResult; + } + + for (Move nextMove : validMoves) { + Board nextBoard = new Board(board); + + if (!nextBoard.playTile(nextMove.getCell(), nextMove.getColor())) { + throw new RuntimeException( + "Illegal move attempted during search!"); + } + + SearchResult searchResult = new SearchResult(nextMove, getMaxValue( + nextBoard, !asHuman, recursionLevel - 1, alpha, beta).score); + + if (searchResult.compareTo(bestResult) < 0) { + bestResult = searchResult; + } + + if (bestResult.score <= alpha) { + return bestResult; + } + + beta = Math.min(beta, bestResult.score); + } + + return bestResult; + } } \ No newline at end of file diff --git a/src/model/comPlayer/generator/ValidMoveGenerator.java b/src/model/comPlayer/generator/ValidMoveGenerator.java index c9a7da2..957fc8e 100644 --- a/src/model/comPlayer/generator/ValidMoveGenerator.java +++ b/src/model/comPlayer/generator/ValidMoveGenerator.java @@ -6,6 +6,7 @@ import java.util.List; import model.Board; import model.Board.TileColor; +import model.CellPointer; import model.Move; import org.apache.log4j.Logger; @@ -25,25 +26,25 @@ public class ValidMoveGenerator implements MoveGenerator { List validMoves = new ArrayList(); - for (int i = 0; i < Board.NUM_ROWS; i++) { - for (int j = 0; j < Board.NUM_COLS; j++) { - if (board.getTile(i, j) == TileColor.NONE) { + 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))) { for (TileColor color : TileColor.values()) { if (color == TileColor.NONE) { continue; } - validMoves.add(new Move(color, i, j)); + validMoves.add(new Move(color, r, c)); } } } } Collections.shuffle(validMoves); - + if (nMoves == MoveGenerator.ALL_MOVES) { return validMoves; } else { - return validMoves.subList(0, Math.min(validMoves.size(),nMoves)); + return validMoves.subList(0, Math.min(validMoves.size(), nMoves)); } } }