Игра крестики-нолики

Kim Jon

Новичок
Пользователь
Авг 1, 2021
16
0
1
1.Windows 10
2. PyCharm 2020.1 на компиляторе Python 3.9
3 Библиотека Random
4
Python:
# Крестики-нолики

import  random

def drawBoard(board):
    #Эта функция выводит на экран игровое поле, клетки которого будут заполнены
    #"board" - это список из 10 строк, для прорисовки игрового поля (индекс 0 игнорируется)
    print(board[7] + '!' + board[8] + '!' + board[9])
    print('-+-+-')
    print(board[4] + '!' + board[5] + '!' + board[6])
    print('-+-+-')
    print(board[1] + '!' + board[2] + '!' + board[3])
    print('-+-+-')

def inputPlayerLater():
    # Разрешение игроку ввести букву, которую он выбирает
    # Возвращает список, в котором буква игрока - первый элемент, а буква компьютера - второй
    letter =''
    while not  (letter == 'X' or letter == 'O'):
        print('Вы выбираете Х или О?')
        letter = input().upper()

    # Первым элементом списка является буква игрока, вторым буква компьютера
    if letter == 'X':
        return ['X','O']
    else:
        return ['O','X']

def whoGoesFirst():
    #Случайный выбор игрока, который ходит первым
    if random.randint(0, 1) == 0:
        return 'Компьютер'
    else:
        return 'Человек'

def makeMove(board, letter, move):
    board[move] = letter

def isWinner(bo, le):
    # Учитывая заполнения игрового поля и буквы игрока, эта функция возвращает True, если игрок выиграл
    # Мы используем bo вместо board и le вместо letter. поэтому нам не жно много печатать
    return ((bo[7]==le and bo[8]==le and bo[9]==le) or # acros the top
            (bo[4]==le and bo[5]==le and bo[6]==le) or # через центр
            (bo[1]==le and bo[2]==le and bo[3]==le) or # через низ
            (bo[7]==le and bo[4]==le and bo[1]==le) or # Вниз по левой стороне
            (bo[8]==le and bo[5]==le and bo[2]==le) or # вниз по центру
            (bo[9]==le and bo[6]==le and bo[3]==le) or # вниз по правой стороне
            (bo[7]==le and bo[5]==le and bo[3]==le) or # по диагонали
            (bo[9]==le and bo[5]==le and bo[1]==le)) # по диагонали
def getBoardCopy(board):
    #Создаеет копию игрового поля и возвращает его
    boardCopy = []
    for i in board:
        boardCopy.append(i)
        return boardCopy
def isSpaceFree(board, move):
    # Возвращает True если сделан ход на свободную клетку.
    return board[move] == ' '
def getPlayerMove(board):
    # Разрешение игроку сделать ход
    move = ' '
    while move not  in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
        print('Ваш следущий ход? (1-9)')
        move = input()
    return int(move)
def chooseRandomMoveFromList(board, moveList):
    # Возвращает допустимый ход, учитывая список сделанных ходов и список заполненных клеток
    # Возвращает значение None, если больше нет допустимых ходов
    possibleMove = []
    for i in moveList:
        if isSpaceFree(board, i):
            possibleMove.append(i)

    if len(possibleMove) != 0:
        return random.choice(possibleMove)
    else:
        return None

def getComputerMove(board, ComputerLetter):
    # Учитывая заполнение игрового поля и букву компьютера, определяет допустимый ход и возвращает его
    if ComputerLetter == 'X':
        playerLetter == 'O'
    else:
        playerLetter = 'X'

    # Это алгоритм для ИИ "Крестиков-Ноликов"
    # Сначала проверяем победим ли мы, сделав следующий ход
    for i in range(1, 10):
        boardCopy = getBoardCopy(board)
        if isSpaceFree(boardCopy, i):
            makeMove(boardCopy, ComputerLetter, i)
            if isWinner(boardCopy, computerLetter):
                return  i
    # Проверяем - победит ли игрок, сделав следующий ход
    for i in range(1, 10):
        boardCopy = getBoardCopy(boardCopy)
        if isSpaceFree(boardCopy, i):
            makeMove(boardCopy, playerLetter, i)
            if isWinner(boardCopy, playerLetter):
                return i
    # Пробуем занять один из углов, если сеть свободные
    move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
    if move != None:
        return  move

    # Пробуем ханять центр если он свободен
    if isSpaceFree(board, 5):
        return  5

    # Делаем ход по одной стороне.
    return  chooseRandomMoveFromList(board, [2, 4, 6, 8])
def isBoardFull(board):
    # Возвращает True, если кетка на игровом поле занята. В противном случае, возвращает False
    for i in range (1, 10):
        if isSpaceFree(board, i):
            return  False
    return True

print('Игра "Крестики-нолики"')

while True:
    # Перезагрузка игрового поля
    theBoard = [' '] * 10
    plaverLetter, computerLetter = inputPlayerLater()
    turn = whoGoesFirst()
    print('' + turn + ' ходит первым.')
    gameIsPlaying = True
while gameIsPlaying:
    if turn == 'Человек':
        # Ход игрока
        drawBoard(theBoard)
        move =getPlayerMove(theBoard)
        makeMove(theBoard, playerLetter, move)
    if isWinner(theBoard, playerLetter):
        drawBoard(theBoard)
        print('Ура! Вы выиграли!')
        gameIsPlaying = False
    else:
        # Ход коспьютера
        move = getComputerMove(theBoard, computerLetter)
        makeMove(theBoard, computerLetter, move)

        if isWinner(theBoard, computerLetter):
            drawBoard(theBoard)
            print('Компьютер победил!. Вы проиграли!')
            gameIsPlaying = False
        else:
            if isBoardFull(theBoard):
                drawBoard(theBoard)
                print('Ничья!')
                break
            else:
                turn = 'Человек'
    print('Сыграем еще раз? (да или нет)')
    if not input().lower().startswith('д'):
        break

Здравствуйте друзья!
Не судите строго, дело в том я только не давно начал изучать этот великолепный язык. И начал я с книги "Делаем крутые игры на Python" автор "Свейгарт Э.". И застрял я на данной теме уже вторую неделю. Дело в том что у меня зациклывается, с самого начала в самом начале. или я чего то не понимаю.1.png Где компьютер ходит первым. Выкладываю скриншот
1.png
Заранее благодарю Вас!!!
 
Последнее редактирование:

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Дело в том что у меня зациклывается, с самого начала в самом начале. или я чего то не понимаю.
Проблема в том, что после выбора игроком символа (крестик или нолик) не реализован выход из цикла while и второй цикл не может запуститься. Чтобы исправить - можно второй цикл сделать вложенным:
Python:
while True:
    # Перезагрузка игрового поля
    theBoard = [' '] * 10
    playerLetter, computerLetter = inputPlayerLater()
    turn = whoGoesFirst()
    print('' + turn + ' ходит первым.')
    gameIsPlaying = True
    while gameIsPlaying:
        if turn == 'Человек':
            # Ход игрока
            drawBoard(theBoard)
            move =getPlayerMove(theBoard)
            makeMove(theBoard, playerLetter, move)
        if isWinner(theBoard, playerLetter):
            drawBoard(theBoard)
            print('Ура! Вы выиграли!')
            gameIsPlaying = False
        else:
            # Ход коспьютера
            move = getComputerMove(theBoard, computerLetter)
            makeMove(theBoard, computerLetter, move)

            if isWinner(theBoard, computerLetter):
                drawBoard(theBoard)
                print('Компьютер победил!. Вы проиграли!')
                gameIsPlaying = False
            else:
                if isBoardFull(theBoard):
                    drawBoard(theBoard)
                    print('Ничья!')
                    break
                else:
                    turn = 'Человек'
        print('Сыграем еще раз? (да или нет)')
        if not input().lower().startswith('д'):
            break
 

Kim Jon

Новичок
Пользователь
Авг 1, 2021
16
0
1
Огромное спасибо! Вы очень помогли
 

Kim Jon

Новичок
Пользователь
Авг 1, 2021
16
0
1
не подскажите почему она ругается на Index что он вне допустимого диапазона. Скрин внизу
Я все еще раз перепроверил. Все отступы и и остальное2.png
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
не подскажите почему она ругается на Index что он вне допустимого диапазона
В функции getBoardCopy нужно возвращать значение не на каждой итерации цикла, а после цикла.
Python:
def getBoardCopy(board):
    #Создаеет копию игрового поля и возвращает его
    boardCopy = []
    for i in board:
        boardCopy.append(i)
    return boardCopy
еще нужно эти строки кода перенести в основной цикл:
Python:
print('Сыграем еще раз? (да или нет)')
    if not input().lower().startswith('д'):
        break
чтобы игра после каждого хода не предлагала начать заново
Python:
while True:
    ...
    while gameIsPlaying:
       ...
    # эти строки должны исполняться после выхода из вложенного цикла
    print('Сыграем еще раз? (да или нет)')
    if not input().lower().startswith('д'):
        break
 

Kim Jon

Новичок
Пользователь
Авг 1, 2021
16
0
1
премного благодарен Вам
 

Kim Jon

Новичок
Пользователь
Авг 1, 2021
16
0
1
Вы бы не могли еще подсказать литературу и видеоуроки по Python 3
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Вы бы не могли еще подсказать литературу и видеоуроки по Python 3
укус питона
видеоуроки по основам питона
видеоуроки по ООП в питоне
видеоуроки по основам асинхронности в питоне
 

Форум IT Специалистов