package edu.dartmouth.cs.kalah; /** * Implements a computer player that chooses moves using * game tree search with alpha-beta pruning * @author Scot Drysdale, 8/2011 */ public class ComputerKalahPlayerGTS extends KalahPlayer { private int depth; // Look-ahead depth /** * Constructs a computer player that uses game tree search * @param name * @param maxDepth */ public ComputerKalahPlayerGTS(String name, int maxDepth) { super(name); depth = maxDepth; } @Override public int getMove(KalahGame state, KalahView view) { int move = pickMove(state, depth).move; view.reportToUser("\n" + state.getPlayerToMove().getName() + " picks pit " + (move - state.getPlayerNum() * KalahGame.HALFPITS)); return move; } /** * Returns the best move and its value for the player after looking * ahead depth moves using game tree search. * @param state current state of the game * @param depth number of moves to look ahead in game tree search * @param depth * @return the move chosen */ private KalahMove pickMove (KalahGame state, int depth) // Returns the best move and its value for the player after looking // ahead depth moves. { KalahMove currentMove; // Hold current move and its value KalahMove bestMove; // Hold best move found and its value int playerKalah, opponentKalah; // Keep track of whose kalah is whose int [] board = state.getBoard(); int playerToMove = state.getPlayerNum(); playerKalah = state.getPlayerNum() * KalahGame.HALFPITS; opponentKalah = KalahGame.HALFPITS - playerKalah; // Set current value to negative infinity so anything will beat it bestMove = new KalahMove(Integer.MIN_VALUE, 0); // Run through possible moves for (int pit = playerKalah + 1; pit <= playerKalah + KalahGame.SIDEPITS; pit++) if (board[pit] > 0) // See if legal move { // Make a scratch copy of state KalahGame copy = new KalahGame(playerToMove, state.getPlayers(), board); copy.makeMove(pit); // Make the move // Find the value of this board by evaluating if game over or looking ahead if not if (copy.gameIsOver()) // Evaluate the true score, and multiply it by a huge constant so that the // program will choose a sure win over a potentially larger speculative win // and a possible loss over a sure loss. currentMove = new KalahMove(100 * copy.score(), pit); else if (playerToMove == copy.getPlayerNum()) // Did current player change? { currentMove = pickMove(copy, depth); // No, so no depth change currentMove.move = pit; // Remember move made } else if (depth > 0) // Player changed, so reduce search depth { currentMove = pickMove(copy, depth - 1); currentMove.value = -currentMove.value; // Good for opponent is bad for me currentMove.move = pit; // Remember move made } else // Depth exhausted, so estimate who is winning by comparing kalahs currentMove = new KalahMove(copy.getBoard()[playerKalah] - copy.getBoard()[opponentKalah], pit); if (currentMove.value > bestMove.value) // Found a new best move? bestMove = currentMove; } return bestMove; } }