Реализуйте окончательный крестики-нолики, но выигрыш на одной вспомогательной доске завершает игру - PullRequest
0 голосов
/ 23 апреля 2019

Я пытаюсь сделать окончательную игру в крестики-нолики на python, которая немного отличается от фактической тем, что эта игра заканчивается, когда есть выигрыш в какой-либо одной подплате. Я использую минимаксный алгоритм с отсечкой альфа-бета, чтобы определить лучший ход для бота. Проблема заключается в том, что когда я запускаю код, и боту пора играть на своем ходу, он работает бесконечно, не приходя к выводу и не возвращая best_move.

Связь с платой уже обработана. Все, что мне нужно, это лучшее значение, и как только я его получу, я смогу извлечь индекс из этого состояния.

Изначально, как только игра запускается, пользователю предлагается сделать шаг от 1 до 9, который затем подается на функцию: Доски - это список из списка, в котором указано состояние каждой дополнительной платы.

# choose a move to play
def play1(user_move):
    # print_board(boards)
    boards_list = main_boards.tolist()
    player = 1
    depth = 20
    end_move = make_bot_move(boards_list, user_move, player, depth)
    place(curr, end_move, 1)
    return end_move

Функция make_bot_move определяет положение человека и определяет, на какой вспомогательной доске он должен сыграть best_move:

def make_bot_move(state, user_move, player, depth):
    #sub_board = state[user_move]
    # if suboptimal(state, user_move, player) != 0:
    #     return suboptimal(state, user_move, player)
    pseudo_states = successors(state, player, user_move)
    best_move = (-inf, None)
    alpha = -inf
    beta = inf
    for x in pseudo_states:
        state = x[0]
        index = x[1]
        val = minimax(state, index, opponent(player), depth-1, alpha, beta)
        if val > best_move[0]:
            best_move = (val, index)
#        print("val = ", val)
#        print_board(s[0])
    return best_move[1]

Функция преемников возвращает возможные состояния, в которых она может выполнить свой ход:

def successors(boards, player, user_move):
    sub_board = boards[user_move]
    value_index = []
    possible_states = []
    for idx, value in enumerate(sub_board):
        if value == 0 and idx != 0:
            value_index.append(idx)
            copied_board = deepcopy(boards)
            possible_states.append(get_possible_state(copied_board, user_move, idx, player))
    #print(possible_states)
    return zip(possible_states, value_index)

Наконец, каждое возможное движение подается в минимаксную функцию, которая возвращает значение наилучшего движения:

def minimax(state, last_move, player, depth, alpha, beta):

    if depth <= 0 or get_game_status(state, player) != 0:
        return evaluate(state, opponent(player))

    if player == 1:
        max_eval = -inf
        pseudo_states = successors(state, player, last_move)
        for x in pseudo_states:
            state = x[0]
            index = x[1]
            print(depth)
            #print_board(np.array(state))
            eval = minimax(state, index, opponent(player), depth-1, alpha, beta)
            max_eval = max(max_eval, eval)
            alpha = max(alpha, eval)
            if beta<= alpha:
                break
        #print_board(np.array(state))
        return max_eval

    if player == 2:
        min_eval = inf
        pseudo_states = successors(state, player, last_move)
        for x in pseudo_states:
            state = x[0]
            index = x[1]
            print(depth)
            #print_board(np.array(state))
            eval = minimax(state, index, opponent(player), depth - 1, alpha, beta)
            min_eval = min(min_eval, eval)
            beta = min(beta, eval)
            if beta<= alpha:
                break
        #print_board(np.array(state))
        return min_eval

Чтобы узнать, выиграл ли кто-то || ПОТЕРЯ || DRAW, функция get_game_status вызывается внутри минимаксной функции:

def get_game_status(state, player):
    other_player = opponent(player)
    for each_box in state[1:10]:
        win_state = [
            [each_box[1], each_box[2], each_box[3]],
            [each_box[4], each_box[5], each_box[6]],
            [each_box[7], each_box[8], each_box[9]],
            [each_box[1], each_box[4], each_box[7]],
            [each_box[2], each_box[5], each_box[8]],
            [each_box[3], each_box[6], each_box[9]],
            [each_box[1], each_box[5], each_box[9]],
            [each_box[3], each_box[5], each_box[7]],
        ]
        if [player, player, player] in win_state:
            return player
        elif [other_player, other_player, other_player] in win_state:
            return other_player
        else:
            return 0

И оценка обрабатывается с помощью функции оценки:

def evaluate(state, player):
    if(get_game_status(state, player) and player ==1) :
        score = 10
    elif(get_game_status(state, player) and player == 2):
        score = -10
    else:
        score = 0
    return score

Ожидаемый результат - получить лучший ход, но вместо этого он работает бесконечно.

Пожалуйста, предложите, какие изменения я должен внести или где я ошибаюсь.

...