def run(self, player, move, last_board, tree_level, is_max, tree_max_depth, use_memcache, alpha, beta, batch_size):
        new_board = ChessUtils.make_move(move, last_board)

        # Extract the set of possible moves for this level of the board.
        is_check, valid_moves = ChessUtils.get_valid_moves(player, new_board)
        
        # By default, continue recursing.
        end_recursion = False 
        # Two recursion stop conditions.
        #------- Condition #1: Recursion Depth of maximum_depth of the tree.
        #------- Condition #2: No more valid player moves.
        if tree_level >= tree_max_depth or len(valid_moves) == 0: 
            end_recursion = True
        
        
        # Ensure only one yield is generated in the case of recursions end so exit.
        if(end_recursion):
            yield common.Return((ChessUtils.get_state_utility(new_board, player, is_max,
		                                                      is_check, valid_moves), None))
        # If child modes will be generated, then generate them as a fan-out then fan them back in.
        else:
            best_util_so_far = alpha if is_max else beta
            best_util_and_move = (best_util_so_far, None)
            yield MakeMoveIter(player, new_board, tree_level, is_max, tree_max_depth, use_memcache, 
                               alpha, beta, batch_size, best_util_and_move, valid_moves)
def main():
    """
    Main client function.  All subsequent calls are made from this function 
    or from functions called by this function.
    
    Params: None
    
    Returns: This function never returns.  Either sys.exit is called directly
    by this function or by one of its subfunctions.
    """
    
    print "\n\nWelcome to the CS218 Spring 2015 Team #2 Chess Playing Program"
    print "\nTeam Members: David Smith, Geetika Garg, and Zayd Hammoudeh\n\n"
    print "Loading the board file...\n\n"
        
    # Error check the inputs.  Ensure a board file was specified.
    if(len(sys.argv) == 1):
        print "No board file was specified.  Exiting."
        sys.exit(0)
        
    # Error check the inputs.  Ensure a board file was specified.
    elif(len(sys.argv) > 2):
        print "Invalid input arguments.  Only a single board file can be specified. Exiting."
        sys.exit(0)
    # Error check the board file exists.
    elif(not os.path.isfile(sys.argv[1])):
        print "The specified board file: \"" + sys.argv[1] + "\" does not appear to exist.  Please check your system and try again."
        sys.exit(0)
    
    # Load the board.
    file_name = sys.argv[1]
    lines = open(file_name).readlines()
    current_player, board =  parse_board(lines)
    print "Board file successfully loaded.\n"
    print "The starting board is:"
    ChessUtils.print_board(board)
    print "\n\n"
    
    # Let the human select whether they are playing black or white.
    human_player = ""
    while(human_player != "0" and human_player != "1"):
        print "Select whether you are playing white or black."
        print "Enter \"0\" for white or \"1\" for black:  ",
        human_player = sys.stdin.readline().strip().replace(" ","") # Take trailing characters and new line off.
        
        if(human_player != "0" and human_player != "1"):
            print "\nInvalid input: \"" + human_player + "\""
            print "A valid input for player color is required before continuing.\n"

    # Convert the string version of player to the integer version. 
    human_player = int(human_player)
    if(human_player == PlayerType.WHITE):
        print "\nYou selected to play as white."
    else:
        print "\nYou selected to play as black."
    print "Starting the game...\n"
    
    # Run the game.
    play_game(current_player, human_player, board)
def make_player_move(check, valid_moves, board):
    """
    Handles the error checking and printing associated with a player
    making a move.
    
    Params:
    current_player : Integer - 0 for white and 1 for black.
    board - List of list of integers of the pieces on the board.
    
    Returns: Tuple of two integers.  Index 0 in the Tuple is the 
    current (i.e. source) location of the piece to be moved
    while index 1 is the new (i.e. destination) location of the piece.
    """
    
    # Keep looping until a valid move is entered.
    next_move = (-1, -1)
    while(next_move not in valid_moves):
        
        next_move = (-1, -1) # Reset next move to a dummy value
        
        if check:
            print "You are in check.  You must enter a move to exit check.\n"
        else:
            print "Its your turn.\n"
        print "Your move should be in the format of two integers separated by a comma."
        print "The first number is the current location of the piece you want to move,"
        print "and the second number is the new location of the piece after the move.\n"
        print "Enter your move: ",
        
        # Get the user text.
        move_text = sys.stdin.readline().strip()
        
        # Split move on comma.
        temp_move = move_text.replace(" ","").split(",")

        # Parse the move.
        if(len(temp_move) == 2):
            try:
                source_loc = int(temp_move[0])
                dest_loc = int(temp_move[1])
                next_move = (source_loc, dest_loc)
                valid_move_text = True
            except:
                # Unable to parse to integer
                valid_move_text = False
        else:
            valid_move_text = False 
        
        # Print messages if the moves are not valid
        if(not valid_move_text):
            print "\nIt does not appear the entered move \"" + move_text + "\" is in the correct format.  Please try again...\n\n"
            ChessUtils.print_board(board)
        # Verify the move is in the move array.
        elif(next_move not in valid_moves):
            print "\nThe specified is not allowed given the current board.  Check your move and try again.\n"
            ChessUtils.print_board(board)   

    # Return the move.
    return next_move 
    def run(self, player, board, tree_max_depth, use_memcache, alpha, beta, batch_size):
        
        # Extract the set of possible moves for this level of the board.
        is_check, valid_moves = ChessUtils.get_valid_moves(player, board)
        
        # Check that the game did not start in an invalid condition.
        if(is_check and len(valid_moves) == 0):
            raise ValueError("Game starting in checkmate.  That is now allowed...")
        
        # If no moves were found to be valid, return an error message.
        if(len(valid_moves) == 0):
            yield common.Return("ERROR - NO VALID MOVES")
        # If only one move is possible, return that.
        elif(len(valid_moves) == 1):
            yield common.Return((0, valid_moves[0]))
        # If there are multiple valid moves, iterate through the possible valid moves.
        else:
            
            # Determine whether white or black is going first.
            if(player == PlayerType.WHITE):
                is_max = True
            else:
                is_max = False 

            # Define the best move and util so far.
            best_util_so_far = alpha if is_max else beta
            best_util_and_move = (best_util_so_far, None)

            # Generate the Minimax tree.
            yield MakeMoveIter(player, board, 1, is_max, tree_max_depth, use_memcache,
                               alpha, beta, batch_size, best_util_and_move, valid_moves)
    def run(self, player, move, board, tree_level, is_max, depth_tree, batch_size, rationality_prob):
        if move:
            board = ChessUtils.make_move(move, board)

        # Extract the set of possible moves for this level of the board.
        is_check, valid_moves = ChessUtils.get_valid_moves(player, board)

        # By default, continue recursing.
        end_recursion = False
        # Two recursion stop conditions.
        # ------- Condition #1: Recursion Depth of 6
        # ------- Condition #2: No more valid player moves.
        if tree_level >= depth_tree or len(valid_moves) == 0:
            end_recursion = True

        # Ensure only one yield is generated in the case of recursions end so exit.
        if end_recursion:
            yield common.Return((ChessUtils.get_state_utility(board, player, is_max, is_check, valid_moves), None))
            return

        if len(valid_moves) == 1:
            yield common.Return(
                (ChessUtils.get_state_utility(board, player, is_max, is_check, valid_moves), valid_moves[0])
            )
            return

        next_player = 1 - player
        is_next_player_max = not is_max
        utilities_and_moves = []
        for new_move in valid_moves:
            utility_and_move = yield InnerExpectiMaxMakeMove(
                next_player,
                new_move,
                board,
                tree_level + 1,
                is_next_player_max,
                depth_tree,  # Required as part of the player increment.
                batch_size,
                rationality_prob,
            )
            utilities_and_moves.append(utility_and_move)
        if tree_level == 2:
            yield DetermineExpectiMaxUtilAndMove(is_max, valid_moves, rationality_prob, *utilities_and_moves)
        else:
            yield DetermineBestUtilAndMove(is_max, valid_moves, *utilities_and_moves)
def query_server(current_player, board):
    """
    Makes a request of the server to get the computer's
    move. 
    
    Params:
    current_player : Integer - 0 for white and 1 for black.
    board - List of list of integers of the pieces on the board.
    
    Returns: Tuple of two integers.  Index 0 in the Tuple is the 
    current (i.e. source) location of the piece to be moved
    while index 1 is the new (i.e. destination) location of the piece.
    """
    
    sys.stdout.write("The computer is thinking about its move  ")
    
    # Create a queue to get the computers move.
    moveQueue = Queue.Queue()

    # Use a thread to get the player's move.
    #server_thread = threading.Thread(target=execute_server_command, args=(current_player, board, moveQueue, tree_max_depth, batch_size, rationality_prob, use_expectimax))
    server_thread = threading.Thread(target=execute_server_command, args=(current_player, board, moveQueue, \
                                                                          tree_max_depth, batch_size))
    
    server_thread.start()
    # Wait for the thread to finish
    while(server_thread.is_alive()):
        sys.stdout.write("*****")
        time.sleep(1)
    sys.stdout.write("\n\n")
    
    # Handle the error case where the network communication crashed.
    if(moveQueue.empty()):
        sys.exit()
    
    computer_move = moveQueue.get(True)
    
    # Allow for two player debug
    if(two_player_debug):
        _, valid_moves = ChessUtils.get_valid_moves(current_player, board)
        computer_move = make_player_move(False, valid_moves, board) # Use player make move as a placeholder.
    return computer_move
    def run(self, player, board, depth_tree, batch_size, rationality_prob):
        # Extract the set of possible moves for this level of the board.
        is_check, valid_moves = ChessUtils.get_valid_moves(player, board)

        if is_check and len(valid_moves) == 0:
            raise ValueError("Game starting in checkmate.  That is now allowed...")

        # If no moves were found to be valid, return an error message.
        if len(valid_moves) == 0:
            yield common.Return("ERROR - NO VALID MOVES")
        # If only one move is possible, return that.
        elif len(valid_moves) == 1:
            yield common.Return((0, valid_moves[0]))
        # If there are multiple valid moves, iterate through the possible valid moves.
        else:
            # Determine whether white or black is going first.
            if player == PlayerType.WHITE:
                is_max = True
            else:
                is_max = False
            yield InnerExpectiMaxMakeMove(player, None, board, 1, is_max, depth_tree, batch_size)
def parse_board(lines):
    '''
    Parse the board from the input file. and return board 
    and the current player
    
    Returns: Type - Tuple
        * Index 0: Current Player (0 or 1)
        * Index 1: Board List of lists.
    
    
    >>> parse_board(["0","0,5,0","11,13, 4"])
    Traceback (most recent call last):
     ...
    ValueError: Invalid board size. It should be a square
    
    >>> parse_board(["0","0,5,0","11,13, 4","0,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: Invalid board. Each player must have exactly one king.
    
    >>> parse_board(["0","0,5,6","11,13, 4","6,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: Invalid board. Each player must have exactly one king.
    
    >>> parse_board(["0","0,5,0","11,13, 4","16,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: Invalid board. Each player must have exactly one king.
    
    >>> parse_board(["0","0,5,16","11,13, 4","16,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: Invalid board. Each player must have exactly one king.
    >>> parse_board(["2","0,5,16","11,13, 4","16,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: File error: Starting player value must be either 0 or 1
    
    >>> parse_board(["2","0,5,6","11,13, 4","16,0,0"])
    Traceback (most recent call last):
     ...
    ValueError: File error: Starting player value must be either 0 or 1

    >>> parse_board(["0","0,5,6","11,13, 4","16,test,0"])
    Traceback (most recent call last):
     ...
    ValueError: The string: "test" could not be converted to an integer for a chess piece.
   
    >>> parse_board(["0","0,5,6","11,13, 4","16,0,0"])
    (0, [[0, 5, 6], [11, 13, 4], [16, 0, 0]])
   
    >>> parse_board(["0","0,5,6","11,13, 4","16,0,0"])
    (0, [[0, 5, 6], [11, 13, 4], [16, 0, 0]])
    
    '''
    try:
        current_player = int(lines[0])
    except ValueError:
        raise ValueError("The string: \"" + lines[0] + "\" could not be converted to an integer for player type.")
        
    if(current_player != PlayerType.BLACK and current_player != PlayerType.WHITE):
        raise ValueError("File error: Starting player value must be either 0 or 1")
    
    
    row = len(lines)-1
    kw = 0
    kb = 0
    board = []
    for line in lines[1:]:
        pieces = line.split(",")
        
        if len(pieces) != row:
            raise ValueError("Invalid board size. It should be a square")

        # Append to the integers to the board but ensure they can be casted correctly.
        try:
            board.append([int(x) for x in pieces]) 
        except ValueError:
            raise ValueError("The string: \"" + x + "\" could not be converted to an integer for a chess piece.")
        
        for piece_player in pieces:

            piece = ChessUtils.get_piece(int(piece_player))
            player = ChessUtils.get_player(int(piece_player))
                
            if player == PlayerType.WHITE and piece == ChessPiece.KING:
                kw += 1
            if player == PlayerType.BLACK and piece == ChessPiece.KING:
                kb += 1

    # Error Check
    if kb != 1 or kw != 1:
        raise ValueError("Invalid board. Each player must have exactly one king.")
        
    return current_player, board
def play_game(current_player, human_player, board):
    '''
    
    Params:
    current_player: Integer - 0 or 1 to indicate whether it is 
    white's or black's turn to start the game.
    
    human_player: Integer - 0 or 1 indicates whether the human player
    is white or black.  This value should not change.
    
    board: List of lists of integers.  It contains the current board.
    It will be updated at the end of each turn.
    
    Returns: 
    This function runs and never returns.  The program exits directly 
    from this function.
    ''' 
    while(True):
        
        check, valid_moves = ChessUtils.get_valid_moves(current_player, board)
        # Check if the game is over.
        if check and len(valid_moves) == 0:
            ChessUtils.print_board(board)
            print "\nCheckmate!"
            if current_player == human_player:
                print "The computer won!  You lose!"
            else:
                print "You win!"
            sys.exit(0)

        # Check if the game is over due to stalemate.
        elif(not check and len(valid_moves) == 0):
            print "\nStalemate!\n"
            print "No moves possible so its a draw!"
            sys.exit(0)
        
        # Print the current board
        print "\n\nCurrent Board:"
        ChessUtils.print_board(board)
        
        # Human's turn.
        if(current_player == human_player):
            # Keep loop until the user enters a valid move.
            next_move = make_player_move(check, valid_moves, board)

        # Computer's turn.
        else:
            if check:
                print "The computer is in check.  It must enter a move to exit check:\n"
            else:
                print "Its the computer's turn.  It is deciding on its move.\n"
            
            next_move = query_server(current_player, board)
            
            # Print the computer's move.
            print "The computer's move is:  (" + str(next_move[0]) + \
                                              ", " + str(next_move[1]) + ")\n"
        
        board = ChessUtils.make_move(next_move, board) # Apply the move.
        current_player = 1 - current_player # update the player
        
    pass