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;
  }

}
