package model.comPlayer.generator; import java.util.Arrays; import java.util.List; import model.Board; import model.BoardScorer; import model.Move; import model.SearchResult; public class AlphaBetaMoveGenerator implements MoveGenerator { private static final int DEFAULT_RECURSIVE_PLAYS = 1; private int lookahead = DEFAULT_RECURSIVE_PLAYS; 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, lookahead * 2, Integer.MIN_VALUE, Integer.MAX_VALUE).move; } else { return getMinValue(board, asHuman, lookahead * 2, Integer.MIN_VALUE, Integer.MAX_VALUE).move; } } /** * AlphaBetaMoveGenerator2 does not support this method. */ @Override public List genMoves(Board board, boolean asHuman, int nMoves) { Move[] doNothing = new Move[] { Move.NONE }; 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; } @Override public boolean setLookahead(int lookahead) { this.lookahead = lookahead; return true; } }