def minimax(board,
            depth,
            player,
            alpha=-np.inf,
            beta=np.inf,
            eval_func='pos_score',
            king_version=False):
    if depth == 0:
        if eval_func == 'pos_score':
            return pos_score_sum(board)
        elif eval_func == 'mobi':
            return mobility(board)
        elif eval_func == 'pos_mobi':
            return pos_plus_mobi(board)
        elif eval_func == 'king_pos_score':  # this is for King Othello
            return king_pos_score_sum(board)
    if not king_version:
        game = Othello()
    else:
        game = KingOthello()
    game.board = board
    game.current_player = player
    possible_moves = game.find_all_valid_moves()

    if possible_moves:
        if player == BLACK:  # maximizing player
            max_eval = -np.inf
            for move in possible_moves:
                game_copy = deepcopy(game)
                game_copy.take_move(move[0], move[1])
                eval = minimax(game_copy.board, depth - 1, opposite(player),
                               alpha, beta)
                max_eval = max(max_eval, eval)
                alpha = max(alpha, eval)
                if beta <= alpha:
                    break
            return max_eval

        else:  # WHITE, minimizing player
            min_eval = np.inf
            for move in possible_moves:
                game_copy = deepcopy(game)
                game_copy.take_move(move[0], move[1])
                eval = minimax(game_copy.board, depth - 1, opposite(player),
                               alpha, beta)
                min_eval = min(min_eval, eval)
                beta = min(beta, eval)
                if beta <= alpha:
                    break
            return min_eval

    else:  # no possible move for current player
        game.switch_turn()
        possible_moves = game.find_all_valid_moves(
        )  # check whether opponent has moves
        if possible_moves:
            return minimax(game.board, depth - 1, opposite(player), alpha,
                           beta)  # hand over to opponent, nothing changed
        else:  # the opponent has no moves either, game over
            return pos_score_sum(game.board)
def mobility(board):
    # defined number of possible moves : black - white
    g1 = Othello()
    g1.board = board
    g1.current_player = BLACK
    score_black = len(g1.find_all_valid_moves())
    g1.current_player = WHITE
    score_white = len(g1.find_all_valid_moves())
    return score_black - score_white