Python крестики-нолики с ИИ

Как сделать так, чтобы вместо 2 игрока играл компьютери просто выбирал рандомные пустые места (с объяснением решения если можно)

    from random import randint
    
    while True:
        BOARD_SIZE = 3
        board = [i for i in range(9)]
        is_winner = False
        current_player = randint(0, 1)
        markers = {0: 'O', 1: 'X'}
        available_turns = (x for x in range(9))
    
        def draw_board():
            res = ""
            for i, v in enumerate(board):
                res += str(v) + " "
                if (i+1) % BOARD_SIZE == 0:
                     res += "\n"
            print(res)
    
        def validate(value = " "):
            if not value.isdigit() and int(value) not in available_turns:
                raise ValueError ("Enter valid value and try again")
            if board[int(value)] in ('X', 'O'):
                raise ValueError ("This value has already played")
            if '.' in value:
                raise ValueError('Number must be int')
    
        def check_winner():
            current_marker = markers[current_player]
            if board[0] == current_marker and board[4] == current_marker and board[8] == current_marker or \
                    board[2] == current_marker and board[4] == current_marker and board[6] == current_marker or \
                    board[0] == current_marker and board[1] == current_marker and board[2] == current_marker or \
                    board[3] == current_marker and board[4] == current_marker and board[5] == current_marker or \
                    board[6] == current_marker and board[7] == current_marker and board[8] == current_marker or \
                    board[0] == current_marker and board[3] == current_marker and board[6] == current_marker or \
                    board[1] == current_marker and board[4] == current_marker and board[7] == current_marker or \
                    board[2] == current_marker and board[5] == current_marker and board[8] == current_marker:
                return True
            else:
                return False
    
        for i in range(9):
            try:
                input_error = True
                draw_board()
                while input_error:
                    choice = input(f"Player {markers[current_player]} enter your number:\n")
                    validate(choice)
                    input_error = False
                board[int(choice)] = markers[current_player]
                if current_player == 1:
                    
                 #проверить победителя
                is_winner = check_winner()
                if is_winner == True:
                    print(f'Player {markers[current_player]} won the game!!')
                    break
                current_player = 0 if current_player == 1 else 1
                # if is_winner == True:
            except ValueError as ex:
                print(ex)
    
        if is_winner == False:
            print('Draw')
        replay = input("Желаете переиграть? (Y or N)")
        if replay == "Y":
            continue
        else:
            break

Ответы (2 шт):

Автор решения: Smart Beetle

Делал такого бота. Пусть крестики - игрок, а нолики - ИИ .Смысл таков:(игрок ходит первый)ВЫ должны проверять 3 клетки по горизонтали, вертикали и диагонали. Если там находится два крестика и нету ноликов, то бот должен поставить нолик в той линии, где два крестика чтобы не проиграть. Если нет такой линии (с двумя крестиками), то бот должен строить свою линию ноликов для победы. Он должен найти такую линию, где нету крестиков и ОБЯЗАТЕЛЬНО с максимальным кол-во ноликов. После того, как он эту линию нашел он должен поставить там нолик. Все это для поля 3х3

→ Ссылка
Автор решения: Роман Орлов

если еще актуально, в интернете есть алгоритм минимакс и его объяснение на примере игры крестики нолики. Сам тоже писал тг бота для крестиков ноликов, использовал этот алгоритм. Алгоритм заключается в том что рекурсионно просчитывает все варианты развития игры для каждой клетки и опираясь на конечный результат игры для каждой клеточки в некоей переменной, привязанной к этой клетке, увеличивает если выиграл бот, уменьшает если человек, не изменяет если ничья. И на основе этой переменной выбирает в какую клетку сходить. Это тяжело звучит, и всю суть я не передал, но сама функция minimax у меня в программе вышла не большая - строк 30-40.

Если будете его использовать, желаю вам не запутаться в рекурсии)

Вот такие консольные крестики нолики получились у меня, но есть одно но: первый ход бот делает почему-то не в центр(что более выгодно), а в угловую клетку(на счет этого есть выход - насильно заставить бота сходить в центр, если он еще пуст). Но в остальном бот играет адекватно. Вот код:


import sys

sys.setrecursionlimit(1000000)  # увеличиваем максимальную глубину рекурсии

huplayer = 'O'
aiplayer = 'X'


class Move:  # класс Ход
    index = -1
    score = 0


def get_empty_cells(board):
    # возвращает список пустых клеток
    l = []
    for i in board:
        if i != 'X' and i != 'O':
            l.append(i)
    return l

def check_win(board, player):
    # Проверяем, выиграл ли player
    if ((board[2] == player and board[4] == player and board[6] == player) or
            (board[0] == player and board[1] == player and board[2] == player) or
            (board[3] == player and board[4] == player and board[5] == player) or
            (board[6] == player and board[7] == player and board[8] == player) or
            (board[0] == player and board[3] == player and board[6] == player) or
            (board[1] == player and board[4] == player and board[7] == player) or
            (board[2] == player and board[5] == player and board[8] == player) or
            (board[0] == player and board[4] == player and board[8] == player)):
        return True
    else:
        return False


def minimax(new_board, player):
    global aiplayer, huplayer
    # доступные клетки
    avail_spots = get_empty_cells(new_board)

    if check_win(new_board, huplayer):
        ret = Move
        ret.score = -10
        return ret
    elif check_win(new_board, aiplayer):
        ret = Move
        ret.score = 10
        return ret
    elif len(avail_spots) == 0:
        ret = Move
        ret.score = 0
        return ret

    moves = []

    for i in range(len(avail_spots)):
        moves.append(Move())
        moves[i].score = 0
        moves[i].index = new_board[avail_spots[i]]

        new_board[avail_spots[i]] = player

        if player == aiplayer:
            moves[i].score += minimax(new_board, huplayer).score
        else:
            moves[i].score += minimax(new_board, aiplayer).score

        new_board[avail_spots[i]] = moves[i].index

    best_move = Move()

    if player == aiplayer:
        best_move.score = -10000
        for i in moves:
            if i.score > best_move.score:
                best_move.score = i.score
                best_move.index = i.index
    else:
        best_move.score = 10000
        for i in moves:
            if i.score < best_move.score:
                best_move.score = i.score
                best_move.index = i.index

    return best_move


def draw_board(board):
    board4draw = []
    for j in board:
        if j in ('X', 'O'):
            board4draw.append(j)
        else:
            board4draw.append(' ')
    for h in range(3):

        print(f'|{board4draw[h*3]}|{board4draw[h*3 + 1]}|{board4draw[h*3 + 2]}|')


def game():
    board = [0, 1, 2, 3, 4, 5, 6, 7, 8]

    # main game loop
    run = True
    global aiplayer, huplayer
    player = aiplayer  # кто первый ходит

    while run:

        if check_win(board, aiplayer):
            print('bot win')
            run = False
            continue
        elif check_win(board, huplayer):
            print('you win')
            run = False
            continue
        empty_cells = get_empty_cells(board)
        if len(empty_cells) != 0:
            if player == aiplayer:
                print('bot made move:')
                bot_move = minimax(board, aiplayer).index
                board[bot_move] = aiplayer
                draw_board(board)
                player = huplayer
                continue
            elif player == huplayer:
                human_move = int(input('ведите цифру: '))
                # human_move = minimax(board, huplayer)
                print('you made move:')
                board[human_move] = huplayer
                draw_board(board)
                player = aiplayer
                continue
        else:
            print('draw')
            run = False


game()


→ Ссылка