Python крестики нолики: Игра крестики-нолики на Python 3 — Пример написания программы с графическим интерфейсом

Содержание

Игра крестики-нолики на Python 3 — Пример написания программы с графическим интерфейсом

Очень полезно в целях изучения языка программирования написать на нем несколько простых программ. Здесь мы представим игру крестики-нолики, которая написана на Python 3 с графическим интерфейсом.

О программе

В этой игре можно помериться силами с компьютером. Первый ход за игроком. Но победить искусственный интеллект в этом противостоянии будет не так уж и просто. Компьютер не делает «зевков» и если у него есть шанс победить, он непременно им воспользуется.

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

Игрок ставит крестики, а компьютер нолики. Как всегда, побеждает тот, кто первый составит линию из своих символов: по горизонтали, вертикали или диагонали.

Библиотеки и объявление переменных

Для отображения графики будем использовать стандартную библиотеку Tkinter, которая устанавливается вместе с Python. Так же нам потребуется библиотека random для того, чтобы получать случайные числа, благодаря которым ходы компьютера будут неожиданными.

Это также стандартная библиотека Python. Так что ничего дополнительно устанавливать не надо. Просто подключаем их с помощью

import. Создаем окно root, устанавливаем ему заголовок и объявляем необходимые переменные:

  • game_run – в эту переменную будем записывать False при завершении игры, чтобы запретить делать ходы когда уже выявлен победитель.
  • field – это будет двумерный список, в котором будут храниться кнопки игрового поля. Ходом будет изменение надписи на кнопке на символ «X» или «O».
  • cross_count в этой переменной мы будем отслеживать количество крестиков на поле. Чтобы по выставлению пятого крестика, в случае если никто не выиграл фиксировать ничью.
from tkinter import *
import random
root = Tk()
root.title('Criss-cross')
game_run = True
field = []
cross_count = 0

Обработка нажатия кнопок

Функция new_game будет вызываться при нажатии кнопки начала новой игры. На поле убираются все крестики и нолики. Цвет кнопок делаем бледно-лиловым. Устанавливаем глобальные переменные game_run и cross_count в начальные значения. Это глобальные переменные к которым пытаемся обратиться из функции. Поэтому перед попыткой изменить их значение, в Python надо использовать ключевое слово global.

def new_game():
    for row in range(3):
        for col in range(3):
            field[row][col]['text'] = ' '
            field[row][col]['background'] = 'lavender'
    global game_run
    game_run = True
    global cross_count
    cross_count = 0

Функция click будет вызываться после нажатия на поле, то есть при попытки поставить крестик. Если игра еще не завершена, то крестик ставится. После этого увеличиваем счетчик количества выставленных крестиков.

Потом проверяем с помощью функции check_win, не победили ли мы этим ходом. Если еще не выявлен победитель и есть еще ходы, то выполняет ход компьютер функцией computer_move, и также после хода идет проверка выигрыша.

def click(row, col):
    if game_run and field[row][col]['text'] == ' ':
        field[row][col]['text'] = 'X'
        global cross_count
        cross_count += 1
        check_win('X')
        if game_run and cross_count < 5:
            computer_move()
            check_win('O')

Проверка победы

Функция check_win осуществляет проверку выигрыша. Она перебирает все возможные комбинации полей, образующих линию и вызывает с ними функцию check_line. Переменная smb – это символ «X» или «O», то есть крестики или нолики. Если задан «O», то проверяется: не победил ли компьютер.

Если зафиксирован выигрыш, то меняем цвет фона кнопок, составляющих линию на розовый. А также записываем в game_run значение False.

def check_win(smb):
    for n in range(3):
        check_line(field[n][0], field[n][1], field[n][2], smb)
        check_line(field[0][n], field[1][n], field[2][n], smb)
    check_line(field[0][0], field[1][1], field[2][2], smb)
    check_line(field[2][0], field[1][1], field[0][2], smb)

def check_line(a1,a2,a3,smb):
    if a1['text'] == smb and a2['text'] == smb and a3['text'] == smb:
        a1['background'] = a2['background'] = a3['background'] = 'pink'
        global game_run
        game_run = False

Проверяем все возможные варианты, так как теоретически можно одним ходом составить сразу 2 линии.

Действия компьютера

Ход компьютера рассчитывается в функции computer_move. Алгоритм его действий следующий:

  1. Проверка возможности победы. Если компьютеру представился шанс победы – он не должен его упустить. Сразу же делает победу.
  2. Проверка возможной победы противника за один ход. Если игрок выставил два крестика в ряд, компьютер пытается разрушить планы игрока.
  3. Случайный ход. Так как победить нет возможности и нет угрозы проигрыша, то выбирается случайное свободное поле. В бесконечном цикле wile перебираются случайные числа, пока они не выпадут на не занятое поле.
def can_win(a1,a2,a3,smb):
    res = False
    if a1['text'] == smb and a2['text'] == smb and a3['text'] == ' ':
        a3['text'] = 'O'
        res = True
    if a1['text'] == smb and a2['text'] == ' ' and a3['text'] == smb:
        a2['text'] = 'O'
        res = True
    if a1['text'] == ' ' and a2['text'] == smb and a3['text'] == smb:
        a1['text'] = 'O'
        res = True
    return res

def computer_move():
    for n in range(3):
        if can_win(field[n][0], field[n][1], field[n][2], 'O'):
            return
        if can_win(field[0][n], field[1][n], field[2][n], 'O'):
            return
    if can_win(field[0][0], field[1][1], field[2][2], 'O'):
        return
    if can_win(field[2][0], field[1][1], field[0][2], 'O'):
        return
    for n in range(3):
        if can_win(field[n][0], field[n][1], field[n][2], 'X'):
            return
        if can_win(field[0][n], field[1][n], field[2][n], 'X'):
            return
    if can_win(field[0][0], field[1][1], field[2][2], 'X'):
        return
    if can_win(field[2][0], field[1][1], field[0][2], 'X'):
        return
    while True:
        row = random.randint(0, 2)
        col = random.randint(0, 2)
        if field[row][col]['text'] == ' ':
            field[row][col]['text'] = 'O'
            break

Графический интерфейс

Все элементы графического интерфейса мы будем размещать с помощью упаковщика grid. В цикле добавим кнопки игрового поля. Они будут храниться в двумерном список. В языке программирования Python добавляют элементы в список с помощью метода append.

Свойство colorspan у кнопки начала игры выставляем в 3, чтобы он занимал всю ширину таблицы

for row in range(3):
    line = []
    for col in range(3):
        button = Button(root, text=' ', width=4, height=2, 
                        font=('Verdana', 20, 'bold'),
                        background='lavender',
                        command=lambda row=row, col=col: click(row,col))
        button.grid(row=row, column=col, sticky='nsew')
        line.append(button)
    field.append(line)
new_button = Button(root, text='new game', command=new_game)
new_button.grid(row=3, column=0, columnspan=3, sticky='nsew')
root.mainloop()

Игровое поле мы делали таким же образом как и кнопки в примере с калькулятором, размещённом в отдельной статье.

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

Крестики-нолики на Python (текстовый вариант)

Сегодня перед нами стоит задача написать игру крестики-нолики на питоне. Напомним, что крестики-нолики это логическая игра для двух игроков на поле 3х3 клетки.

Для начала зададим поле. Поле у нас будет одномерным списком (list) с числами от 1 до 9. Для создания воспользуемся функцией range()

board = range(1,10)

Теперь напишем функцию, которая будет выводить наше поле в привычном формате.

def draw_board(board):
    print "-------------"
    for i in range(3):
        print "|", board[0+i*3], "|", board[1+i*3], "|", board[2+i*3], "|"
        print "-------------"

Результат выполнения данного кода

Самое время дать пользователям возможность вводить данные в нашу игру. Пишем функцию take_input

def take_input(player_token):
	valid = False
	while not valid:
		player_answer = raw_input("Куда поставим " + player_token+"? ")
		try:
			player_answer = int(player_answer)
		except:
			print "Некорректный ввод. Вы уверены, что ввели число?"
            continue
		if player_answer >= 1 and player_answer <= 9:
			if (str(board[player_answer-1]) not in "XO"):
				board[player_answer-1] = player_token
				valid = True
			else:
				print "Эта клеточка уже занята"
		else:
			print "Некорректный ввод. Введите число от 1 до 9 чтобы походить."

Как вы видите, функция take_input принимает параметр player_token — крестик или нолик, в зависимости от того, чей сейчас ход. Нам важно ограничить выбор пользователя числами от 1 до 9. Для этого мы используем конструкции try/except и if/else, чтобы удостовериться, что выбранная клеточка не занята. Обратите внимание, что функция take_input не возвращает никакого значения, а только изменяет имеющийся список board.

Осталось написать функцию проверки игрового поля. Назовем эту функцию check_win.

def check_win(board):
	win_coord = ((0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6))
	for each in win_coord:
		if board[each[0]] == board[each[1]] == board[each[2]]:
			return board[each[0]]
	return False 

Проверка результатов игры крестики-нолики достаточно распространенная задача по программированию. Как часто бывает, одно и то же задание в программировании можно решить несколькими способами. В данном случае мы просто создали кортеж (tuple) с выигрышными координатами и прошлись циклом for по нему. Если символы во всех трех заданных клетках равны — возвращаем выигрышный символ, иначе — возвращаем значение False. При этом важно помнить, что непустая строка (наш выигрышный символ) при приведении ее к логическому типу вернет True (это понадобится нам в дальнейшем).

Осталось создать функцию main, в которой мы соберем вместе все описанные функции.

def main(board):
	counter = 0
	win = False
	while not win:
		draw_board(board)
		if counter % 2 == 0:
			take_input("X")
		else:
			take_input("O")
		counter += 1
		if counter > 4:
			tmp = check_win(board)
			if tmp:
				print tmp, "выиграл!"
				win = True
				break
		if counter == 9:
			print "Ничья!"
			break
	draw_board(board)

Работа функции main предельно понятна, разве что строки 45 и 46 могут вызвать непонимание. Мы ждем когда переменная counter станет больше 4 для того, чтобы избежать заведомо ненужного вызова функции check_win (до пятого хода никто точно не может выиграть). Переменная tmp была создана опять же для того, чтобы лишний раз не вызывать функцию check_win, мы просто «запоминаем» ее значение и при необходимости используем на строке 48. Польза от такого подхода не так заметна при работе с небольшими объемами данных, но в целом подобная экономия процессорного времени — хорошая практика.

Теперь мы можем спокойно играть, запустив main(board)

 

И последнее уточнение. Для того, чтобы у вас корректно отображались символы кириллицы вставьте следующий код в самое начало вашего файла.

# -*- coding: utf-8 -*-

 Хорошей игры!

PS. Исходный код игры крестики-нолики на Python 3 на github

Python: нестандартные функции. Игра “Крестики-нолики”.

Продолжаем учить язык программирования пайтон Python. Переходим к изучению 6 главы “Функции. Игра Крестики-нолики” по книге: Майкл Доусон “Программируем на Python”, 2014 (Michael Dawson “Python Programming for the Absolute Beginner”, 3rd Edition), чтобы создавать собственные функции и работать с глобальными переменными.

Как создать функцию?

Общий вид функции в Python: название_функции()

Чтобы создать собственную функцию, нужно ее объявить.

Общий вид объявления функции

def название_функции(параметр1, параметр2...):
    '''Документирующая строка'''
    Блок выражений функции

Функции могут:

  • принимать значения через параметры,
  • возвращать значения через return.

Параметр функции

— это имя переменной в скобках после названия функции. В момент объявления функции параметр может не иметь конкретного значения. При вызове функции параметру нужно присвоить значение.

Позиционные параметры функции

В функции можно перечислить несколько параметров:

def название_функции(параметр1, параметр2...):

Вызов этой функции с позиционными аргументами:

название_функции('значение параметра1',значение параметра2...)

Вызов этой функции с именованными аргументами (для них не важен порядок!):

название_функции(параметр1='значение параметра1', параметр2=значение параметра2,...)

равнозначно…

название_функции(параметр2=значение параметра2, параметр1='значение параметра1',...)

Параметры по умолчанию

def название_функции(параметр1='значение', параметр2=значение...):

Если при вызове функции никакие другие значения параметрам не присвоятся, то отобразятся значения параметров по умолчанию.

Присваивая значение по умолчанию одному параметру, это нужно сделать для всех остальных параметров в объявляемой функции.

Параметры по умолчанию можно переопределить при вызове функции, при чем переопределять их можно и по отдельности, а не все сразу. Например, так:

Объявление функции ->

def название_функции(параметр1='значение', параметр2=значение):

Вызов функции ->

название_функции(параметр1='значение параметра1')

Функция, которая возвращает значения

def vozvrat():
    imya='kot'
    return imya

Программа-иллюстрация:

def vozvrat():
    imya='kot'
    return imya
print('Возврат: ', vozvrat())

Запуск программы дает:

Возврат:  kot
>>> 

Можно возвращать несколько значений через запись return p1,p2,p3...

Функция main()

Основной код программы можно не оставлять в глобальной зоне видимости, а поместить в функцию, которое можно дать любое имя, например, main()

Тогда код запуска программы будет выглядеть так:

main()
input('Нажмите Entr, чтобы выйти')

Глобальные переменные

Переменные внутри функции доступны только там. Есть глобальные переменные, которые объявляются вне функций, при этом они доступны внутри функций тоже, то только для “чтения”, если не указано обратное.

Глобальная переменная — создается в общей области видимости.

Локальная переменная — создается внутри функции.

Изменение глобальной переменной внутри функции

Чтобы менять глобальные переменные, находясь внутри функции, пишем global

Если создана глобальная переменная g_peremennaya, то изменить ее внутри функции можно написав: global g_peremennaya

Затенение глобальной переменной

Так как в общем случае внутри функции нельзя изменить значение глобальной переменной, но можно создать одноименную переменную внутри функции. Это и будет затенение. Новая одноименная переменная будет работать только внутри функции. Но это вносит путаницу, лучше так не делать.

Глобальные константы

Переменные мы изменяем по ходу кода. А константы — это переменные, записанные большими буквами (CONSTANTA), которые мы решили не менять. В общем случае лучше использовать глобальные константы, чем глобальные переменные.

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

Задача: написать программу, в которой пользователь может играть с компьютером в крестики-нолики на поле 3х3. Сначала показывается инструкция к игре. Далее идет выбор, кто будет ходить первым. Начинается игра, игроки делают ходы по очереди. Когда кто-то выигрывает или игра сыграна вничью, выводятся результаты и программа завершает работу.

Начнем с создания собственной функции, которая будет показывать пользователю инструкцию к игре:

def instrukciya():
    print('''
Привет! Это игра "Крестики-нолики".
Чтобы сделать ход, введи номер клетки,
куда хочешь поставить свой символ:

0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8


''')

Игра начинается с того, что пользователь выбирает, кто делает первый ход. Для этого напишем функцию, которая задает пользователю вопрос “Вы хотите быть первым, кто сделает ход (играть крестиками)?”, на который можно ответить “да” или “нет”. В объявлении функции можно на задавать конкретный вопрос, можно написать просто vopros, а потом при вызове функции в скобках написать любой текст.

Чтобы реализовать этот блок программы, сначала объявим первую общую функцию, которая будет задавать вопрос и получать ответ “да” или “нет”:

def nachalo(vopros):
    otvet=None
    while otvet not in ('да','нет'):
        otvet=input(question).lower()
    return otvet

Вторая часть функции присваивает игрокам тип фишек в зависимости от того, кто ходит первый, и будет состоять из уже объявленной функции nachalo(vopros):

def fishki():
    perviy_hod=nachalo("Вы хотите быть первым, кто сделает ход \
(играть крестиками)?  ")
    if perviy_hod=='да':
        print('Окей, ты играешь крестиками!')
        human=Х
        comp=O
    else:
        print('ОК, я делаю первый крестиками')
        human=O
        comp=Х
    return human, comp

В этих двух функциях мы используем имена переменных Х и O, чтобы компьютер правильно их использовал в игре, нужно дополнительно ввести эти переменные на глобальном уровне. То есть объяснить, что значит X и O:

Глобально задаем переменные:

X='X'
O='0'

Далее в программе нужно сделать функцию, которая будет спрашивать о том, куда пользователь хочет поставить свою фишку. Поле будет 3х3 и каждому полю условно дается свой номер от 0 до 8. То есть нужно сделать функцию, куда пользователь введет номер клетки для своего хода.

def hod(vopros,low,high):
    otvet=None
    while otvet not in range(low,high):
        otvet=int(input(vopros))
    return otvet

Сделаем функцию, которая генерирует игровые поля:

  • потребуется две глобальные константы: RAZMER_DOSKI и HODI
RAZMER_DOSKI=9 HODI=' '

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

def new_doska():
    doska=[]
    for i in range(RAZMER-DOSKI):
        doska.append(HODI)
    return doska

Теперь нужно сделать функцию, которая будет показывать пользователю доску с результатом каждого хода:

def pokaz_doski(doska):
    print('\n', board[0], '|', board[1], '|', board [2])
    print('---------')
    print('\n', board[3], '|', board[4], '|', board [5])
    print('---------')
    print('\n', board[6], '|', board[7], '|', board [8], '\n')

Нам еще потребуется функция, которая проверяет, куда можно пойти. Для этого нужно сделать функцию с перебором всех пустых клеток, чтобы все незанятые места добавились в список, который и есть “доступные ходы”:

def dostupnie_hodi(doska):
    dostupnie_hodi=[]
    for i in range(RAZMER_DOSKI):
        if doska(i)== HODI:
            dostupnie_hodi.append(i)
    return dostupnie_hodi

Отдельно сделаем функцию, которая выводит победителя. Если победит игрок, ставящий крестики, то функция выдаст X, если победитель играл ноликами — 0, ничья задается глобальной константой NICHYA='Ничья', если игра еще не дошла до конца, то функция выдаст None. Есть способ определения победы через перебор всех возможных наборов из трех клеток, при которых игрок считается победителем:

def winner(doska):
    VAR_POBED=((0,1,2),
               (3,4,5),
               (6,7,8),
               (0,3,6),
               (1,4,7),
               (2,5,8),
               (0,4,8),
               (2,4,6))
    for i in varianti_pobed:
        if doska[i[0]]==doska[i[1]]==doska[i[2]]!=HODI:
            winner=doska[i[0]]
            return winner
        if HODI not in doska:
            return NICHYA
    return None

Следующая функция учитывает ходы пользователя, для этого нужно сначала понять, куда можно пойти, затем ожидается ввод пользователя числа из доступных. Функция принимает доску и тип фишек пользователя. В итоге работы функции пользователь делает ход:

def human_hod(doska,human):
    dostupnie=dostupnie_hodi(doska)
    hod=None
    while hod not in dostupnie:
        hod=hod('Твоя очередь ходить. Напиши номер поля 0-8: ',\
 0,RAZMER_DOSKI)
        if hod not in dostupnie:
            print('Поле занято. Напиши другой номер: ')
    print('Супер!')
    return hod

Пришло время самой сложной для меня функции — это ходы компьютера. Нужно, чтобы компьютер делал “хорошие” ходы, старался выиграть у пользователя. Ходить наугад можно, если компьютер будет выбирать любое свободное место на поле. Но тогда ему будет трудно выиграть.

Чтобы не “испортить” исходную доску, опытные программисты советуют создавать внутри функции “копию” доски, в которую мы и будем вносить изменения:

def comp_hod(doska,comp,human):
    doska=doska[:]

Чтобы компьютер не ходил “от балды”, учтем следующую стратегию:

  • “лучшее” поле – по центру;
  • если центральное поле уже занято, то “лучшими” считаются угловые поля;
  • компьютер ходит в “лучшее” из свободных мест на поле.

Лучшие поля задаются константой внутри функции:

BEST_HODI=(4,0,2,6,8,1,3,5,7)

В итоге вся функция ходов компьютера получается такой:

def comp_hod(doska,comp,human):
    doska=doska[:]
    BEST_HODI=(4,0,2,6,8,1,3,5,7)
    print('Мой ход: ')
    for i in dostupnie_hodi(doska):
        doska[i]=comp
        if winner(doska)==comp:
            print(hod)
            return hod
        doska[i]=HODI
    for j in dostupnie_hodi(doska):
        doska[j]=human
        if winner(doska)==human:
            print(hod)
            return hod
        doska[j]=HODI
    for k in dostupnie_hodi(doska):
        print(k)
        return k

Нужна еще одна функция, которая будет давать сделать ход следующему игроку, определяя какими фишками был сделан последний ход и передавая ход другим фишкам:

def next_hod(hod):
    if hod==X:
        return O
    else:
        return X

Потребуется еще функция, которая выявит победителя и поздравит пользователя с окончанием игры. Эта функция будет использоваться только в самом конце игры:

def pozdrav_pobeditela(pobeditel,comp,human):
    if pobeditel!=NICHYA:
        print('Собрана линия ', pobeditel)
    else:
        print(NICHYA)
    if pobeditel==comp:
        print('/n Компьютер выиграл!')
    elif pobeditel==human:
        print('Ты победил!')
    elif pobeditel==NICHYA:
        print(NICHYA)

Когда у нас есть все функции, нужно записать общую функцию main(), которая объединит все отдельные функции в единое целое:

def main():
    instrukciya()
    comp,human=fishki()
    hod=X
    doska=new_doska()
    pokaz_doski(doska)
    while not winner(doska):
        if i==human:
            hod=human_hod(doska,human)
            doska[hod]=human
        else:
            hod=comp_hod(doska,comp,human)
            doska[hod]=comp
        pokaz_doski(doska)
        i=next_hod(hod)
    pobeditel=winner(doska)
    pozdrav_pobeditela(pobeditel,comp,human)

Попробуем запустить программу с игрой “Крестики-Нолики”, для запуска потребуется всего две строки кода:

main()
input('\n Нажми Entr, чтобы выйти')

Запуск программы показал, что игра не работает как надо. Несмотря на то, что логика построения программы верная, в самих функциях где-то допущены ошибки. Нужно их исправить.

Исправление ошибок в игре “Крестики-нолики”.

Тестирование программы игры и исправление ошибок оказалось довольно трудной задачей, чтобы сделать это “на глаз”. Как искать ошибки в программе? Наверное, лучший способ — это протестировать работу каждой функции отдельно. Запустим каждую функцию и посмотрим, где есть проблемы:

Функция instrukciya() работает:

Привет! Это игра "Крестики-нолики".
Чтобы сделать ход, введи номер клетки,
куда хочешь поставить свой символ:

0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8



>>> 

Запускаем функцию fishki(), и с ней все в порядке:

Вы хотите быть первым, кто сделает ход (играть крестиками)?  да
Окей, ты играешь крестиками!
>>> 

В функции hod(low,high) я решила добавить конкретный вопрос, и ее запуск тоже прошел успешно со значениями 0-8 hod(0,8):

Делай свой ход - напиши номер поля (0-8): 2
>>> 

Запуск функции new_doska() ошибок не выдал, но и результата тоже, так как изначально этот блок пустой.

Спустя еще пару часов блужданий по коду, поиска ошибок, запусков отдельных функций и групп функций, я обнаружила, что в нескольких местах знак “крестика” X был написан разными символами, а также кое-где крестик стоял в кавычках. Еще некоторые мелочи были исправлены. Конечный вариант кода программы (которая заработала и выиграла у меня!) выглядит так:

X='X'
O='0'
RAZMER_DOSKI=9
HODI=' '
NICHYA='Ничья'

def instrukciya():
    print('''
Привет! Это игра "Крестики-нолики".
Чтобы сделать ход, введи номер клетки,
куда хочешь поставить свой символ:

0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8


''')
def nachalo(vopros):
    otvet=None
    while otvet not in ('да','нет'):
        otvet=input(vopros).lower()
    return otvet

def fishki():
    perviy_hod=nachalo("Вы хотите быть первым, кто сделает ход \
(играть крестиками)?  ")
    if perviy_hod=='да':
        print('Окей, ты играешь крестиками!')
        human=X
        comp=O
    else:
        print('ОК, я делаю первый ход крестиками')
        human=O
        comp=X
    return comp, human
        
def hod_number(low,high):
    otvet=None
    while otvet not in range(low,high):
        otvet=int(input("Делай свой ход - напиши номер поля (0-8): "))
    return otvet


def new_doska():
    doska=[]
    for i in range(RAZMER_DOSKI):
        doska.append(HODI)
    return doska

def pokaz_doski(doska):
    print('\n', doska[0], '|', doska[1], '|', doska [2])
    print('---------')
    print('\n'
          , doska[3], '|', doska[4], '|', doska [5])
    print('---------')
    print('\n', doska[6], '|', doska[7], '|', doska [8], '\n')

def dostupnie_hodi(doska):
    dostupnie_hodi=[]
    for i in range(RAZMER_DOSKI):
        if doska[i]== HODI:
            dostupnie_hodi.append(i)
    return dostupnie_hodi

def winner(doska):
    VAR_POBED=((0,1,2),
               (3,4,5),
               (6,7,8),
               (0,3,6),
               (1,4,7),
               (2,5,8),
               (0,4,8),
               (2,4,6))
    for i in VAR_POBED:
        if doska[i[0]]==doska[i[1]]==doska[i[2]]!=HODI:
            winner=doska[i[0]]
            return winner
        if HODI not in doska:
            return NICHYA
    return None
def human_hod(doska,human):
    dostupnie=dostupnie_hodi(doska)
    hod=None
    while hod not in dostupnie:
        hod=hod_number(0,RAZMER_DOSKI)
        if hod not in dostupnie:
            print('Поле занято. Напиши другой номер: ')
    print('Супер!')
    return hod
def comp_hod(doska,comp,human):
    doska=doska[:]
    BEST_HODI=(4,0,2,6,8,1,3,5,7)
    print('Мой ход: ')
    for i in dostupnie_hodi(doska):
        doska[i]=comp
        if winner(doska)==comp:
            print(i)
            return i
        doska[i]=HODI
    for j in dostupnie_hodi(doska):
        doska[j]=human
        if winner(doska)==human:
            print(j)
            return j
        doska[j]=HODI
    for k in dostupnie_hodi(doska):
        print(k)
        return k
def next_ochered(ochered):
    if ochered==X:
        return O
    else:
        return X
def pozdrav_pobeditela(pobeditel,comp,human):
    if pobeditel!=NICHYA:
        print('Собрана линия ', pobeditel)
    else:
        print(NICHYA)
    if pobeditel==comp:
        print('Компьютер выиграл!')
    elif pobeditel==human:
        print('Ты победил!')
    elif pobeditel==NICHYA:
        print(NICHYA)
def main():
    instrukciya()
    comp,human=fishki()
    ochered=X
    doska=new_doska()
    pokaz_doski(doska)
    while not winner(doska):
        if ochered==human:
            hod=human_hod(doska,human)
            doska[hod]=human
        else:
            hod=comp_hod(doska,comp,human)
            doska[hod]=comp
        pokaz_doski(doska)
        ochered=next_ochered(ochered)
    pobeditel=winner(doska)
    pozdrav_pobeditela(pobeditel,comp,human)

main()
input('\n Нажми Entr, чтобы выйти')

Мой первый матч в крестики-нолики с компьютером выглядел так:

Привет! Это игра "Крестики-нолики".
Чтобы сделать ход, введи номер клетки,
куда хочешь поставить свой символ:

0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8



Вы хотите быть первым, кто сделает ход (играть крестиками)?  да
Окей, ты играешь крестиками!

   |   |  
---------

   |   |  
---------

   |   |   

Делай свой ход - напиши номер поля (0-8): 4
Супер!

   |   |  
---------

   | X |  
---------

   |   |   

Мой ход: 
0

 0 |   |  
---------

   | X |  
---------

   |   |   

Делай свой ход - напиши номер поля (0-8): 5
Супер!

 0 |   |  
---------

   | X | X
---------

   |   |   

Мой ход: 
3

 0 |   |  
---------

 0 | X | X
---------

   |   |   

Делай свой ход - напиши номер поля (0-8): 2
Супер!

 0 |   | X
---------

 0 | X | X
---------

   |   |   

Мой ход: 
6

 0 |   | X
---------

 0 | X | X
---------

 0 |   |   

Собрана линия  0
Компьютер выиграл!

 Нажми Entr, чтобы выйти

 

Играем в Крестики-Нолики с Python и GTK / Хабр

Предисловие

Новый блог GTK+ порадовал статьёй для начинающих и я решил попробовать что-то более простое, чем C++/C. Python оказался как нельзя кстати. Объём кода на Python для работы с GTK значительно меньше чем на C++, что не может не радовать.
PyGTK

PyGTK — биндинг библиотеки GTK для языка Python, PyGTK используется во многих открытых программах (например IM Gajim). Библиотека может быть очень интересна для Python программистов, поскольку проста в обращении и полностью скрывает реализацию GTK.

Под катом пример приложения.

Пример приложения

Для изучения PyGTK я решил написать простой пример — игру Крестики-Нолики.
Окно игры будет максимально простым — квадрат из кнопок 3×3.

Окно игры:

Итак приступим к реализации. В программе есть пара классов: XO_Field и XO_Win, первый хранит информацию о поле, второй создаёт GUI для приложения и обрабатывает события.

Я использовал для примера модуль pygtk, установленный из пакетного менеджера в Ubuntu, на других системах стоит воспользоваться пакетами или python easy-install, а для Windows есть инсталлятор.

Используем модуль pygtk версии 2.0 или старше:

import pygtk
pygtk.require('2.0')
import gtk

Создадим простое окно, по закрытию которого будем прерывать и цикл событий GTK. Функция destroy будет приведена чуть позже.
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", self.destroy)
self.window.set_title("Крестики-Нолики.py!")
self.window.set_border_width(10)
self.window.set_size_request(400,400)

Для окна воспользуемся вертикальной компоновкой из трёх строк с горизонтальной.
Так кнопки будут расположены как раз в виде квадрата 3×3. Для каждой из кнопок добавляется обработчик события «clicked», синтаксис добавления очень похож на сигналы и слоты в Qt.
self.vbox = gtk.VBox(False,0)
self.window.add(self.vbox)
        
for i in range(3):
    box = gtk.HBox(False,0)
    self.boxes.append(box)
    for j in range(3):
        self.buttons[i].append(self.create_button(box))
        self.buttons[i][j].connect("clicked",self.on_btn_click,i,j)
    self.vbox.pack_start(box,True,True,0)
    box.show()

Функция, создающая кнопку:
def create_button(self,box):
    button = gtk.Button(self.field.chr)
    box.pack_start(button,True,True,0)
    button.show()
    return button

Запуск основного цикла событий GTK и уничтожение окна:
def main(self):
    gtk.main()

def destroy(self, widget, data=None):
    gtk.main_quit()

По нажатию на кнопки происходит установка знака в указанную позицию и переход хода к следующему игроку, если ещё не определён победитель. Если игра завершена, результат выводится в заголовок окна.

Сама игра в Крестики-Нолики и её реализация довольно тривиальна, ссылка на исходный код приведена ниже. Больший интерес представляет сам цикл работы приложения Python в связке с GTK, так например сборщик мусора при сборке ссылок на объекты GTK также вызывает деструкторы для них, поскольку элементы UI содержат много ссылок на ресурсы.

P.S.
Лучшим решением было бы использовать GtkTable (контейнер для выравнивания виджетов по сетке) с 3 строками и 3 столбцами, но как-то вспомнил о нём поздно.
Со временем API GTK обновляется, как было замечено в комментариях, есть уже биндинг для gtk 3. Стоит постепенно переходить на него, но не до конца ясен вопрос с поддержкой gtk 3 на платформах, отличных от linux.

Весь исходный код примера

Источники
  1. PyGTK на Wiki
  2. Сайт проекта PyGTK
  3. О компоновке и виджетах

Глава 10.1 Исходный код игры «Крестики-Нолики».

Как всегда, я настоятельно советую набирать программу самостоятельно. Это и практика и программу понимать вы будете лучше. Впрочем, вы всегда можете скачать образец программы на странице «Загрузки«.

Итак, откройте новое окно текстового редактора Python Shell, наберите приведенный ниже код и сохраните в файле с названием ‘TicTacToe.py’ Впрочем, файл можете назвать как захотите. Но если вы потом решите конвертировать программу в *.exe — формат, то могут возникнуть проблемы с символами кириллицы в названии.

1. #Крестики-Нолики
2.
3. import random
4.
5. def drawBoard(board):
6.     #Эта функция рисует игровую доску с выполненными ходами
7.
8.     #"Доска" является списком из 10 строк которые рисуют доску в 
символьной графике
9.     print(' | |')
10.    print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
11.    print(' | |')
12.    print('---+---+---')
13.    print(' | |')
14.    print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
15.    print(' | |')
16.    print('---+---+---')
17.    print(' | |')
18.    print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
19.    print(' | |')
20.
21. def inputPlayerLetter():
22.     #Позволяет игроку выбрать символ, которым он хочет играть
23.     #Возвращает список с буквой игрока в качестве первого элемента и 
буквой компьютера в качестве второго элемента
24.     letter = ''
25.     while not (letter == 'Х' or letter == 'О'):
26.         print('Каким знаком вы будете играть? (Х или О)')
27.         letter = input().upper()
28.
29.     #Первым элементом возвращаемого списка всегда должен быть знак игрока.
30.     if letter == 'Х':
31.         return ['Х', 'О']
32.     else:
33.         return ['О', 'Х']
34.
35. def whoGoesFirst():
36.     #Случайно определяется, кто будет ходить первым
37.     if random.randint(0, 1) == 0:
38.         return 'компьютер'
39.     else:
40.         return 'игрок'
41.
42. def playAgain():
43.     #Эта функция возвращает True, если игрок хочет сыграть еще раз. 
Иначе False.
44.     print('Вы хотите сыграть еще раз? (да или нет)')
45.     return input().lower().startswith('д')
46. 
47. def makeMove(board, letter, move):
48.     board[move] = letter
49. 
50. def isWinner(bo, le):
51.     #Функция учитывает позицию на доске и текщий ход игрока. Возвращает 
True, если игрок выиграл
52.     #Мы используем bo вместо доски и le вместо полных имен переменных
53.     return ((bo[7] == le and bo[8] == le and bo[9] == le) or #Верхняя линия
54.     (bo[4] == le and bo[5] == le and bo[6] == le) or #Средняя линия
55.     (bo[1] == le and bo[2] == le and bo[3] == le) or #Нижняя линия
56.     (bo[7] == le and bo[4] == le and bo[1] == le) or #Левая вертикальная линия
57.     (bo[8] == le and bo[5] == le and bo[2] == le) or #Центральная вертикаль
58.     (bo[9] == le and bo[6] == le and bo[3] == le) or #Верхняя линия
59.     (bo[7] == le and bo[5] == le and bo[3] == le) or #Диагональ
60.     (bo[9] == le and bo[5] == le and bo[1] == le)) #Диагональ
61. 
62. def getBoardCopy(board):
63.     #Сделаем копию игровой доски и вернем её
64.     dupeBoard = []
65. 
66.     for i in board:
65.         dupeBoard.append(i)
67.
68.     return dupeBoard
69. 
70. def isSpaceFree(board, move):
71.     #Возвращает True если ход возможен
72.     return board[move] == ' '
73. 
74. def getPlayerMove(board):
75.     #Позволяет игроку выполнить ход
76.     move = ''
77.     while move not in '1 2 3 4 5 6 7 8 9'.split() or not 
isSpaceFree(board, int(move)):
78.         print('Ваш ход (1-9):')
79.         move = input()
80.     return int(move)
81. 
82. def chooseRandomMoveFromList(board, movesList):
83.     #Возвращает случайный ход из полученного списка возможных ходов
84.     #Возвращает None если ходов нет
85.     possibleMoves = []
86.     for i in movesList:
87.         if isSpaceFree(board, i):
88.             possibleMoves.append(i)
89. 
90.     if len(possibleMoves) != 0:
91.         return random.choice(possibleMoves)
92.     else:
93.         return None
94. 
95. def getComputerMove(board, computerLetter):
96.     #Получает копию содержимого доски и букву, которой ходит компьютер. 
Исходя из этого определяет куда двигаться и возвращает ход
97.     if computerLetter == 'Х':
98.         playerLetter = 'О'
99.     else:
100.        playerLetter = 'Х'
101. 
102.    #Здесь начинается алгоритм ИИ "Крестики-Нолики"
103.    #Первым шагом будет определение возможности победы на следующем ходу
104.    for i in range(1, 10):
105.        copy = getBoardCopy(board)
106.        if isSpaceFree(copy, i):
107.            makeMove(copy, computerLetter, i)
108.            if isWinner(copy, computerLetter):
109.                return i
110 
111.    #Проверяем, может ли игрок выиграть на следющем ходу, чтобы 
заблокировать его
112.    for i in range(1, 10):
113.        copy = getBoardCopy(board)
114.        if isSpaceFree(copy, i):
115.            makeMove(copy, playerLetter, i)
116.            if isWinner(copy, playerLetter):
117.                return i
118. 
119.     #Попытаемся занять один из углов, если они свободны
119.     move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
120.     if move != None:
121.         return move
122. 
123.     #Занимаем центр, если он свободен
124.     if isSpaceFree(board, 5):
125.         return 5
126. 
127.     #Занимаем одну из боковых клеток
128.     return chooseRandomMoveFromList(board, [2, 4, 6, 8])
129. 
130. def isBoardFull(board):
131.     #Возвращаем True, если все клетки на доске были заняты. Иначе 
возвращаем False
132.     for i in range(1, 10):
133.         if isSpaceFree(board, i):
134.             return False
135.     return True
136
137.
138. print ('Давай сыграем в "Крестики-Нолики"!')
139
140. while True:
141.     #Сбрасываем состояние игровой доски
142.     theBoard = [' ']*10
143.     playerLetter, computerLetter = inputPlayerLetter()
144.     turn = whoGoesFirst()
145.     print ('Первым будет ходить '+turn +'\n')
146.     gameIsPlaying = True
147. 
148.     while gameIsPlaying:
149.         if turn == 'игрок':
150.             #Ход игрока
151.             drawBoard(theBoard)
152.             move = getPlayerMove(theBoard)
153.             makeMove(theBoard, playerLetter, move)
154. 
155.             if isWinner(theBoard, playerLetter):
156.                 drawBoard(theBoard)
157.                 print ('Поздравляю!!! Вы победили в игре!')
158.                 gameIsPlaying = False
159.             else:
160.                 if isBoardFull(theBoard):
161.                     drawBoard(theBoard)
162.                     print('Ничья. В следующий раз играй лучше')
163.                     break
164.                 else:
165.                     turn = 'компьютер'
166. 
167.         else:
168.             #Ход компьютера
169.             move = getComputerMove(theBoard, computerLetter)
170.             makeMove(theBoard, computerLetter, move)
171.             if isWinner(theBoard, computerLetter):
172.                 drawBoard(theBoard)
173.                 print('Компьютер победил! Вы поиграли...')
174.                 gameIsPlaying = False
175.             else:
176.                 if isBoardFull(theBoard):
177.                     drawBoard(theBoard)
178.                     print('Ничья. В следующий раз играй лучше')
179.                     break
180.                 else:
181.                     turn = 'игрок'
182. 
183.     if not playAgain():
185          break

Обсудить на форуме.

Поделиться ссылкой:

Понравилось это:

Нравится Загрузка…

Похожее

Глава 10. Игра «Крестики-Нолики» на Python 3

Темы, рассматриваемые в этой главе:

  • Искусственный интеллект
  • Список ссылок
  • Short-Circuit Evaluation (переведу как только разберусь что это 😉 )
  • Значение None (пустое)

В этой главе мы рассмотрим игру, которая знакома всем и каждому – «Крестики-нолики». Вам предстоит сыграть в нее против несложного искусственного интеллекта. Искусственный интеллект (далее по тексту – ИИ), это программа, которая оценивает действия игрока и на их основе выбирает собственную тактику действий. В этой игре не будет никаких сложных концепций. На практике, ИИ «Крестики-нолики», это всего лишь несколько строк кода.

Для начала вспомним, как в «Крестики-нолики» играют два человека. На листе бумаги расчерчивается поле,  размером 3х3 клетки. Один игрок – Х, второй – О.  Игроки по очереди ставят свои символы (Х или О). Победителем становится тот, кому удастся выстроить три своих символа в ряд по вертикали, горизонтали или диагонали. Если это не удается сделать ни одному из игроков, а свободных клеток не осталось, то результатом игры становится ничья.

Для создания ИИ «Крестики-нолики», за некоторыми исключениями, будет достаточно тех знаний, которые вы приобрели, изучая предыдущие главы. Давайте начнем изучение этой программы с одиночного запуска игры «Крестики-нолики».

Одиночный запуск программы «Крестики-нолики».

Рис 10-1. Одиночный запуск программы «Крестики-Нолики» в консоли Windows 7.

Обсудить на форуме.

Поделиться ссылкой:

Понравилось это:

Нравится Загрузка…

Похожее

Tic tac toe крестики-нолики

import numpy as np
import random
from operator import itemgetter
 
board = np.array([['_', '_', '_'],
                  ['_', '_', '_'],
                  ['_', '_', '_']], dtype=str)
 
SIGN = {0: 'X', 1: 'O'}
 
MATRIX = np.array([[0,1,2],
                  [3,4,5],
                  [6,7,8]])
 
def board_print(board):
    """Эта функция отображает поле с заполнеными клетками"""
 
    print('--------------')
    print('| {} | {} | {} |'.format(board[0,0], board[0,1], board[0,2]))
    print('| {} | {} | {} |'.format(board[1,0], board[1,1], board[1,2]))
    print('| {} | {} | {} |'.format(board[2,0], board[2,1], board[2,2]))
    print('--------------')
 
def choice_sign():
    """Выбор крестика или нолика"""
    sign = input("""Выберите свой знак:
                0 - крестик,
                1 - нолик)\n""")
    user_sign = SIGN[int(sign)]
    comp_sign = SIGN[0] if int(sign) == 1 else SIGN[1]
 
    return user_sign, comp_sign
 
def choice_step():
    """Выбор первого хода, 0 - человек, 1 -компьютер"""
    step = random.randint(0,1)
    if step == 0:
        print('Поздравляю, Вы ходите первым!')
        return True
    else:
        print('Первым выпал шанс ходить компьютеру')
        return False
 
def choice_cell(board):
    """Выбирает клетку для хода"""
    board_print(board)
    print('Выберите строку и столбец, где будет стоять ваш знак')
    while True:
        cell = input("""Вам нужно ввести два числа. Первое - строка, второе - столбец:
                      1 - первая строка или столбец
                      2 - вторая строка или столбце
                      3 - третья строка или столбец
                      будьте внимательны, ячейки могут быть заняты
                    \n""")
        if len(cell) != 2:
            print('Введите не одно, а два числа')
            continue
        # в pythone нумерация начинается с 0
        row = int(cell[0]) - 1
        column = int(cell[1]) - 1
 
        if row in range(0, 3) and \
                column in range(0,3) and \
                board[row, column] == '_':
            break
        else:
            print('Неверно выбрана ячейка проверьте внимательно')
    return row, column
 
 
 
class GameState:
    def __init__(self, board, comp_sign, user_sign):
        self.board = board
        self.comp_sign = comp_sign
        self.user_sign = user_sign
        self.winning_combos = [((0,0), (0,1), (0,2)), ((1,0), (1,1), (1,2)), #(0,1,2) (3,4,5)
                              ((2,0), (2,1), (2,2)), ((0,0), (1,0), (2,0)), #(6,7,8) (0,3,6)
                                ((0,1), (1,1), (2,1)), ((0,2), (1,2), (2,2)), #(1,4,7) (2,5,8)
                              ((0,0), (1,1), (2,2)), ((0,2), (1,1), (2,0))]   #(0,4,8) (2,4,6)
 
    def get_winner(self):
        '''Возвращает None если игра всё ещё продолжается, иначе оценка с точки зрения компьютера (1=победа, 0=ничья, -1=проигрыщ)'''
        if np.count_nonzero(self.board == '_') == 0: #если не осталось пустых полей
            return 0
        for combo in self.winning_combos:
            if (self.board[combo[0]] == self.comp_sign and
                self.board[combo[1]] == self.comp_sign and
                self.board[combo[2]] == self.comp_sign):
                return 1
            if (self.board[combo[0]] == self.user_sign and
                self.board[combo[1]] == self.user_sign and
                self.board[combo[2]] == self.user_sign):
                return 1
        return None
 
    def get_possible_moves(self):
        '''Возвращает все возможные ячейки для размещения символов'''
        return [index for index, square in np.ndenumerate(self.board) if square == '_']
 
    def get_next_state(self, move, our_turn):
        '''Возвращает состояние игры после заполнения ячейки'''
        copy_array = np.copy(self.board)
        copy_array[move] = self.comp_sign if our_turn else self.user_sign
        return GameState(copy_array, self.comp_sign, self.user_sign)
 
def play(game_state, our_turn):
    '''Если игра закончена, возвращает (None, score), в противном случае рекурсивно находит лучший ход и возвращает его и счёт'''
    score = game_state.get_winner() # может быть None, 0, 1, -1
    if score != None:
        return None, score
    moves = ((move,
              play(game_state.get_next_state(move, our_turn), not our_turn)[1])
             for move in game_state.get_possible_moves())
    return (max if our_turn else min)(moves, key=itemgetter(1))
 
def main():
    print('Начинаем игру')
    user_sign, comp_sign = choice_sign() #игрок выбирает знак
 
    start_game_state = GameState(board, comp_sign, user_sign)
 
    if choice_step():
        # игрок выбирает куда поставить знак
        # choice_cell возвращает кортеж, а сам принимает текущую доску
        start_game_state.board[choice_cell(start_game_state.board)] = user_sign
 
    board_print(start_game_state.board)
    # Ищет лучший ход и очки
    move, score = play(start_game_state, True)
 
    start_game_state.board[move] = comp_sign
 
    while score != 1 or score != 0:
        if score == 0:
            word = 'TIE'
        elif score == 1:
            word = 'WIN'
        else:
            word = 'LOSS, who rigged the board?!?'
        print('X should go at index #', move, 'Which will always result in a ' + word)
        start_game_state.board[choice_cell(start_game_state.board)] = user_sign
        move, score = play(start_game_state, True)
        print('SCORE',score)
        #if score == -1:
            #break
        start_game_state.board[move] = comp_sign
    board_print(start_game_state.board)
 
 
 
main()

Здравствуйте, подскажите пожалуйста, как доработать игру крестики-нолики, а то у меня после последнего крестика всё поле вдруг становится ноликами ((


Крестики-нолики с использованием Python — AskPython

В этой статье мы рассмотрим этапы создания крестиков-ноликов с использованием языка Python с нуля.

Крестики-нолики

Об игре

Крестики-нолики — это игра для двух игроков, в которую играют на квадратной сетке 3 × 3. Каждый игрок по очереди занимает ячейку с целью разместить три метки по горизонтали, вертикали или диагонали. Один игрок использует крест 'X' в качестве маркера, а другой использует нулевое значение 'O' .


Шаг 1: Дизайн крестиков-ноликов

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

Крестики-нолики Дизайн

Если игрок должен отметить конкретное поле, он должен ввести соответствующий номер, показанный в сетке. Предположим, мы хотим занять центральный блок, тогда мы введем 5 в терминал. Эту сетку можно создать с помощью:

# Функция для печати Tic Tac Toe
def print_tic_tac_toe (значения):
печать ("\ п")
печать ("\ t | |")
print ("\ t {} | {} | {}".формат (значения [0], значения [1], значения [2]))
print ('\ t _____ | _____ | _____')

печать ("\ t | |")
print ("\ t {} | {} | {}". формат (значения [3], значения [4], значения [5]))
print ('\ t _____ | _____ | _____')

печать ("\ t | |")

print ("\ t {} | {} | {}". формат (значения [6], значения [7], значения [8]))
печать ("\ t | |")
печать ("\ п")
 

В приведенном выше коде функция создает нашу игру в крестики-нолики в соответствии со значениями, переданными в качестве аргумента. Здесь аргумент значений — это список, содержащий статус каждой ячейки в сетке.


Шаг 2. Сохранение информации с использованием структур данных

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

В любой момент нам нужны две важные информации:

  • Статус сетки — У нас должна быть структура данных, в которой хранится состояние каждой ячейки, то есть занята она или свободна.
  • Ходы каждого игрока Мы должны каким-то образом знать прошлые и настоящие ходы каждого игрока, то есть позиции, занятые 'X' и 'O' .

Примечание: Обе информации можно было бы получить, используя статус сетки, но требовалось бы пересекать ее каждый раз, когда нам нужны позиции игрока. Это можно назвать компромиссом между временем и сложностью пространства. Это общий метод экономии времени.

# Функция для одиночной игры Tic Tac Toe
def single_game (cur_player):

# Представляет крестики-нолики
values ​​= ['' для x в диапазоне (9)]

# Сохраняет позиции, занятые X и O
player_pos = {'X': [], 'O': []}
 

Статус сетки управляется списком символов, который может иметь три возможных значения,

  • '' — Свободная ячейка
  • 'X' — Ячейка, занятая игроком X
  • 'O' — Ячейка, занятая игроком O

Ходы каждого игрока сохраняются как словарь списка целых чисел.Ключи: 'X' и 'O' для соответствующего игрока. Соответствующие им списки содержат номера, присвоенные ячейкам сетки, которые они занимают.

Примечание: Переменная cur_player хранит текущего игрока, делающего ход, как в 'X' или 'O' .


Шаг 3: игровой цикл

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

# Game Loop для одиночной игры Tic Tac Toe
в то время как True:
print_tic_tac_toe (значения)
 

Шаг 4. Обработка ввода игрока

На каждой итерации игры игрок должен ввести свой ход.

# Попробуйте блокировку исключений для ввода MOVE
пытаться:
print ("Игрок", cur_player, "поворот. Какой ящик?:", end = "")
переместить = int (вход ())
кроме ValueError:
print («Неверный ввод !!! Попробуйте еще раз»)
Продолжать

# Проверка работоспособности для MOVE inout
если перемещение <1 или перемещение> 9:
print («Неверный ввод !!! Попробуйте еще раз»)
Продолжать

# Проверить, не занят ли ящик
если значения [move-1]! = '':
print ("Место уже заполнено.Попробуй снова!!")
Продолжать
 

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

Нам нужно выполнить некоторые проверки работоспособности, например, введенное значение является действительной позицией, и если это действительная позиция, она уже занята?


Шаг 5: Обновите информацию

Согласно вводу игрока, нам необходимо обновить информацию для бесперебойной работы игры.

# Обновить информацию об игре

# Обновление статуса сетки
значения [move-1] = cur_player

# Обновление позиций игроков
player_pos [cur_player] .append (переместить)
 

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

После обновления списка значений и вызова функции print_tic_tac_toe () сетка выглядит следующим образом:

Крестики-нолики после 5 ходов.
Последний ход: «X» на 2

Шаг 6: Проверьте выигрыш или ничью

После каждого хода мы должны проверять, выиграл ли какой-либо игрок партию или игра была сделана вничью. Его можно проверить по:

Вызов функций:

# Вызов функции для проверки выигрыша
если check_win (player_pos, cur_player):
print_tic_tac_toe (значения)
print ("Игрок", cur_player, "выиграл игру !!")
печать ("\ п")
вернуть cur_player

# Вызов функции для проверки розыгрыша игры
если check_draw (player_pos):
print_tic_tac_toe (значения)
print ("Игра нарисована")
печать ("\ п")
вернуть 'D'
 

Если какой-либо игрок выигрывает, функция single_game () возвращает текущего игрока, который сделал ход.В случае ничьей, 'D' отправляется обратно.

Функции:

# Функция, чтобы проверить, выиграл ли какой-либо игрок
def check_win (player_pos, cur_player):

# Все возможные выигрышные комбинации
soln = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 4, 7], [2, 5, 8], [3, 6, 9] » , [1, 5, 9], [3, 5, 7]]

# Цикл, чтобы проверить, удовлетворена ли какая-либо выигрышная комбинация
для x в soln:
если все (y в player_pos [cur_player] для y в x):

# Возвращаем True, если удовлетворяет любая выигрышная комбинация
вернуть True
# Возвращаем False, если комбинация не удовлетворяет
return False

# Функция проверки, нарисована ли игра
def check_draw (player_pos):
если len (player_pos ['X']) + len (player_pos ['O']) == 9:
вернуть True
return False
 

check_win () — Функция содержит все выигрышные комбинации.Все, что он делает, это проверяет, удовлетворяется ли какая-либо из выигрышных комбинаций текущими позициями игрока. Если это так, он возвращает True . Если ни одна из комбинаций не удовлетворена, функция возвращает False .

check_draw () — Условие розыгрыша довольно простое, так как игра заканчивается, когда все «девять» позиций заняты.


Шаг 7: переключить текущего игрока

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

# Сменить ходы игрока
если cur_player == 'X':
cur_player = 'О'
еще:
cur_player = 'X'
 

Что касается одиночной игры, это все, что нам нужно сделать. Но в этой статье также представлена ​​система табло для отслеживания, если игроки хотят сыграть в несколько игр.


Шаг 8: Введите имена игроков

Имя каждого игрока обязательно должно отображаться на любом табло.

если __name__ == "__main__":

print ("Игрок 1")
player1 = input ("Введите имя:")
печать ("\ п")

print ("Игрок 2")
player2 = input ("Введите имя:")
печать ("\ п")
 

Шаг 9: Сохраните информацию об игре

Информация, такая как текущий игрок, выбор игроков (взять крестик или ноль), доступные варианты (крестик и ноль) и табло, должны быть сохранены.

# Сохраняет игрока, который выбирает X и O
cur_player = player1

# Хранит выбор игроков
player_choice = {'X': "", 'O': ""}

# Сохраняет параметры
options = ['X', 'O']

# Хранит табло
score_board = {player1: 0, player2: 0}
 

По умолчанию текущий игрок — это игрок, который первым ввел имя.


Шаг 10: Дизайн табло

Табло хранится в виде словаря, где ключи — это имена игроков, а значения — их выигрышные числа.

# Функция для печати табло
def print_scoreboard (score_board):
Распечатать("--------------------------------")
print ("ДОСКА СЧЕТОВ")
Распечатать("--------------------------------")

игроки = список (score_board.keys ())
print ("", игроки [0], "", Score_board [игроки [0]])
print ("", игроки [1], "", Score_board [игроки [1]])

print ("-------------------------------- \ n")
 

Для отображения табло нам нужны имена игроков. Ключи извлекаются с помощью .keys () , а затем преобразуется в список, чтобы его можно было индексировать при отображении оценок.


Шаг 11: Внешний игровой цикл

Нам нужен еще один игровой цикл, для управления множеством матчей в крестики-нолики. Каждый матч текущий игрок выбирает свою отметку ( 'X' или 'O' ). Меню выбора должно отображаться на каждой итерации игры:

# Game Loop для серии Tic Tac Toe
# Цикл продолжается до тех пор, пока игроки не выйдут
в то время как True:

# Меню выбора игрока
print ("Поверните, чтобы выбрать", cur_player)
print ("Введите 1 для X")
print ("Введите 2 вместо O")
print («Введите 3, чтобы выйти»)
 

Табло и меню выглядят так:

Табло и меню

Шаг 12: Обработка и назначение выбора игрока

На каждой итерации мы должны обрабатывать и сохранять выбор текущего игрока.

# Попробуйте исключение для ввода CHOICE
пытаться:
выбор = int (вход ())
кроме ValueError:
print ("Неправильный ввод !!! Попробуйте еще раз \ n")
Продолжать

# Условия выбора игрока
если выбор == 1:
player_choice ['X'] = cur_player
если cur_player == player1:
player_choice ['O'] = player2
еще:
player_choice ['O'] = player1

elif choice == 2:
player_choice ['O'] = cur_player
если cur_player == player1:
player_choice ['X'] = player2
еще:
player_choice ['X'] = player1

elif choice == 3:
print ("Окончательные результаты")
print_scoreboard (табло_счетов)
сломать

еще:
print ("Неправильный выбор !!!! Попробуйте снова \ n")
 

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


Шаг 13: Выполнить сопоставление

После сохранения всей необходимой информации пора выполнить независимый матч и сохранить выигрышный знак.

# Сохраняет победителя в одиночной игре в крестики-нолики
победитель = single_game (варианты [выбор-1])
 

Шаг 14: Обновите табло

Нам нужно обновлять табло после каждого матча крестики-нолики.

# Обновляет табло в соответствии с победителем
если победитель! = 'D':
player_won = player_choice [победитель]
Score_board [player_won] = Score_board [player_won] + 1

print_scoreboard (табло_счетов)
 

Если игра не закончилась вничью, то обновляем табло.


Шаг 15: Сменить игрока

Это прекрасная идея, что каждый игрок должен иметь возможность выбирать, какой знак он хочет. Для этого меняем местами значение в cur_player .

# Сменить игрока, который выбирает X или O
если cur_player == player1:
cur_player = player2
еще:
cur_player = player1
 

Полный рабочий код

# Функция для печати Tic Tac Toe
def print_tic_tac_toe (значения):
печать ("\ п")
печать ("\ t | |")
print ("\ t {} | {} | {}". формат (значения [0], значения [1], значения [2]))
print ('\ t _____ | _____ | _____')

печать ("\ t | |")
print ("\ t {} | {} | {}". формат (значения [3], значения [4], значения [5]))
print ('\ t _____ | _____ | _____')

печать ("\ t | |")

print ("\ t {} | {} | {}".формат (значения [6], значения [7], значения [8]))
печать ("\ t | |")
печать ("\ п")


# Функция для печати табло
def print_scoreboard (score_board):
print ("\ t --------------------------------")
print ("\ t ДОСКА СЧЕТОВ")
print ("\ t --------------------------------")

игроки = список (score_board.keys ())
print ("\ t", игроки [0], "\ t", табло [игроки [0]])
print ("\ t", игроки [1], "\ t", табло [игроки [1]])

print ("\ t -------------------------------- \ n")

# Функция, чтобы проверить, выиграл ли какой-либо игрок
def check_win (player_pos, cur_player):

# Все возможные выигрышные комбинации
soln = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 4, 7], [2, 5, 8], [3, 6, 9] » , [1, 5, 9], [3, 5, 7]]

# Цикл, чтобы проверить, удовлетворена ли какая-либо выигрышная комбинация
для x в soln:
если все (y в player_pos [cur_player] для y в x):

# Возвращаем True, если удовлетворяет любая выигрышная комбинация
вернуть True
# Возвращаем False, если комбинация не удовлетворяет
return False

# Функция проверки, нарисована ли игра
def check_draw (player_pos):
если len (player_pos ['X']) + len (player_pos ['O']) == 9:
вернуть True
return False

# Функция для одиночной игры Tic Tac Toe
def single_game (cur_player):

# Представляет крестики-нолики
values ​​= ['' для x в диапазоне (9)]

# Сохраняет позиции, занятые X и O
player_pos = {'X': [], 'O': []}

# Game Loop для одиночной игры Tic Tac Toe
в то время как True:
print_tic_tac_toe (значения)

# Попробуйте блокировку исключений для ввода MOVE
пытаться:
print ("Игрок", cur_player, "поворот.Какая коробка? : ", end =" ")
переместить = int (вход ())
кроме ValueError:
print («Неверный ввод !!! Попробуйте еще раз»)
Продолжать

# Проверка работоспособности для MOVE inout
если перемещение <1 или перемещение> 9:
print («Неверный ввод !!! Попробуйте еще раз»)
Продолжать

# Проверить, не занят ли ящик
если значения [move-1]! = '':
print («Место уже заполнено. Попробуйте еще раз !!»)
Продолжать

# Обновить информацию об игре

# Обновление статуса сетки
значения [move-1] = cur_player

# Обновление позиций игроков
player_pos [cur_player].добавить (переместить)

# Вызов функции для проверки выигрыша
если check_win (player_pos, cur_player):
print_tic_tac_toe (значения)
print ("Игрок", cur_player, "выиграл игру !!")
печать ("\ п")
вернуть cur_player

# Вызов функции для проверки розыгрыша игры
если check_draw (player_pos):
print_tic_tac_toe (значения)
print ("Игра нарисована")
печать ("\ п")
вернуть 'D'

# Сменить ходы игрока
если cur_player == 'X':
cur_player = 'О'
еще:
cur_player = 'X'

если __name__ == "__main__":

print ("Игрок 1")
player1 = input ("Введите имя:")
печать ("\ п")

print ("Игрок 2")
player2 = input ("Введите имя:")
печать ("\ п")

# Сохраняет игрока, который выбирает X и O
cur_player = player1

# Хранит выбор игроков
player_choice = {'X': "", 'O': ""}

# Сохраняет параметры
options = ['X', 'O']

# Хранит табло
score_board = {player1: 0, player2: 0}
print_scoreboard (табло_счетов)

# Game Loop для серии Tic Tac Toe
# Цикл продолжается до тех пор, пока игроки не выйдут
в то время как True:

# Меню выбора игрока
print ("Поверните, чтобы выбрать", cur_player)
print ("Введите 1 для X")
print ("Введите 2 вместо O")
print («Введите 3, чтобы выйти»)

# Попробуйте исключение для ввода CHOICE
пытаться:
выбор = int (вход ())
кроме ValueError:
print ("Неправильный ввод !!! Попробуйте еще раз \ n")
Продолжать

# Условия выбора игрока
если выбор == 1:
player_choice ['X'] = cur_player
если cur_player == player1:
player_choice ['O'] = player2
еще:
player_choice ['O'] = player1

elif choice == 2:
player_choice ['O'] = cur_player
если cur_player == player1:
player_choice ['X'] = player2
еще:
player_choice ['X'] = player1

elif choice == 3:
print ("Окончательные результаты")
print_scoreboard (табло_счетов)
сломать

еще:
print ("Неправильный выбор !!!! Попробуйте снова \ n")

# Сохраняет победителя в одиночной игре Tic Tac Toe
победитель = single_game (варианты [выбор-1])

# Редактирует табло в соответствии с победителем
если победитель! = 'D':
player_won = player_choice [победитель]
Score_board [player_won] = Score_board [player_won] + 1

print_scoreboard (табло_счетов)
# Сменить игрока, который выбирает X или O
если cur_player == player1:
cur_player = player2
еще:
cur_player = player1
 

Пора поиграть!

Все шаги по созданию игры завершены.Пришло время поиграть в игру.

Игрок 1
Введите имя: Луффи


Игрок 2
Введите имя: Санджи


--------------------------------
ТАБЛО
--------------------------------
Луффи 0
Санджи 0
--------------------------------

Повернись, чтобы выбрать Луффи
Введите 1 для X
Введите 2 для O
Введите 3, чтобы выйти
1


| |
| |
_____ | _____ | _____
| |
| |
_____ | _____ | _____
| |
| |
| |


Игрок X ход.Какая коробка? : 5


| |
| |
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
| |
| |


Игрок O ход. Какая коробка? : 1


| |
O | |
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
| |
| |


Игрок X ход. Какая коробка? : 9


| |
O | |
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
| | Икс
| |


Игрок O ход.Какая коробка? : 2


| |
O | O |
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
| | Икс
| |


Игрок X ход. Какая коробка? : 3


| |
O | O | Икс
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
| | Икс
| |


Игрок O ход. Какая коробка? : 7


| |
O | O | Икс
_____ | _____ | _____
| |
| X |
_____ | _____ | _____
| |
O | | Икс
| |


Игрок X ход.Какая коробка? : 6


| |
O | O | Икс
_____ | _____ | _____
| |
| X | Икс
_____ | _____ | _____
| |
O | | Икс
| |


Игрок X выиграл игру !!


--------------------------------
ТАБЛО
--------------------------------
Луффи 1
Санджи 0
--------------------------------

Повернись, чтобы выбрать Санджи
Введите 1 для X
Введите 2 для O
Введите 3, чтобы выйти
2


| |
| |
_____ | _____ | _____
| |
| |
_____ | _____ | _____
| |
| |
| |


Игрок O ход.Какая коробка? : 5


| |
| |
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| |
| |


Игрок X ход. Какая коробка? : 3


| |
| | Икс
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| |
| |


Игрок O ход. Какая коробка? : 2


| |
| O | Икс
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| |
| |


Игрок X ход.Какая коробка? : 8


| |
| O | Икс
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| X |
| |


Игрок O ход. Какая коробка? : 1


| |
O | O | Икс
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| X |
| |


Игрок X ход. Какая коробка? : 9


| |
O | O | Икс
_____ | _____ | _____
| |
| O |
_____ | _____ | _____
| |
| X | Икс
| |


Игрок O ход.Какая коробка? : 6


| |
O | O | Икс
_____ | _____ | _____
| |
| O | О
_____ | _____ | _____
| |
| X | Икс
| |


Игрок X ход. Какая коробка? : 7


| |
O | O | Икс
_____ | _____ | _____
| |
| O | О
_____ | _____ | _____
| |
X | X | Икс
| |


Игрок X выиграл игру !!


--------------------------------
ТАБЛО
--------------------------------
Луффи 2
Санджи 0
--------------------------------

Повернись, чтобы выбрать Луффи
Введите 1 для X
Введите 2 для O
Введите 3, чтобы выйти
3
Окончательные результаты
--------------------------------
ТАБЛО
--------------------------------
Луффи 2
Санджи 0
--------------------------------
 


Заключение

Мы надеемся, что эта статья была интересной и информативной для читателя.Я также загрузил код на Github. Вы можете посетить здесь для получения кода. Если есть какие-то предложения по игре, не стесняйтесь комментировать.


.

Игра «Крестики-нолики» на Python

В этой статье я покажу вам, как создать очень простую игру «Крестики-нолики» в консольном приложении C #.

Введение

Крестики-нолики — очень простая игра для двух игроков. Таким образом, одновременно могут играть только два игрока. Эта игра также известна как «крестики-нолики» или «крестики-нолики». Один игрок играет с X, а другой — с O. В этой игре у нас есть доска, состоящая из сетки 3×3. Количество сеток может быть увеличено.

Доска в крестики-нолики выглядит следующим образом:

Правила игры

  1. Традиционно первый игрок играет с «Х». Таким образом, вы можете решить, кто хочет выбрать «X», а кто — «O».
  2. Только один игрок может играть одновременно.
  3. Если кто-то из игроков заполнил квадрат, то другой игрок и тот же игрок не могут отменить этот квадрат.
  4. Есть только два условия, при которых может совпадать ничья или может быть победа.
  5. Игрок, которому удастся разместить три соответствующих знака (X или O) в горизонтальном, вертикальном или диагональном ряду, выигрывает игру.

Условие выигрыша

Победителем будет тот, кто поставит три соответствующие отметки (X или O) по горизонтали, вертикали или диагонали.

Код для игры следующий:

  1. import os
  2. import time
  3. board = [», », », », », », », ‘ ‘,’ ‘,’ ‘]
  4. player = 1
  5. ######## флаги win ##########
  6. Win = 1
  7. Draw = -1
  8. Работает = 0
  9. Стоп = 1
  10. ###################################
  11. Игра = Запуск
  12. Отметка = ‘X’
  13. # Эта функция рисует игровое поле
  14. def DrawBoard ():
  15. print («% c |% c |% c»% (доска [1], доска [2], доска [3]))
  16. print («___ | ___ | ___»)
  17. print («% c |% c |% c»% (доска [4], доска [5], доска [6]))
  18. print («___ | ___ | ___ «)
  19. печать («% c |% c |% c «% (доска [7], доска [8], доска [9]))
  20. печать (» | | «)
  21. 9001 5
  22. # Эта функция проверяет пустую позицию или нет
  23. def CheckPosition (x):
  24. if (board [x] == »):
  25. return True
  26. else:
  27. return False
  28. # Эта функция проверяет, выиграл ли игрок
  29. def CheckWin ():
  30. global Game
  31. # Горизонтальное условие выигрыша
  32. if (board [1] == board [2] and board [2] == board [3] ] И доска [1]! = »):
  33. Game = Win
  34. elif (доска [4] == доска [5] и доска [5] == доска [6] и доска [4]! = ‘ ‘):
  35. Game = Win
  36. elif (доска [7] == доска [8] и доска [8] == доска [9] и доска [7]! =’ ‘):
  37. Game = Win
  38. # Вертикальное условие выигрыша
  39. elif (доска [1] == доска [4] и доска [4] == доска [7] и доска [1]! = »): 90 016
  40. Game = Win
  41. elif (доска [2] == доска [5] и доска [5] == доска [8] и доска [2]! = »):
  42. Game = Win
  43. elif ( доска [3] == доска [6] и доска [6] == доска [9] и доска [3]! = »):
  44. Game = Win
  45. #Diagonal Winning Condition
  46. elif (board [1 ] == доска [5] и доска [5] == доска [9] и доска [5]! = »):
  47. Game = Win
  48. elif (доска [3] == доска [5] и доска [5] == доска [7] и доска [5]! = »):
  49. Game = Win
  50. # Match Tie or Draw Condition
  51. elif (board [1]! = » And board [2] ! = » And board [3]! = » And board [4]! = » And board [5]! = » And board [6]! = » And board [7]! = » И board [8]! = » и board [9]! = »):
  52. Game = Draw
  53. else:
  54. Game = Запуск
  55. print («Ti Игра c-Tac-Toe, разработанная Сурабом Сомани »)
  56. print (« Игрок 1 [X] — Игрок 2 [O] \ n »)
  57. print ()
  58. print ()
  59. print (« Пожалуйста Подождите… «)
  60. time.sleep (3)
  61. while (Game == Running):
  62. os.system (‘cls’)
  63. DrawBoard ()
  64. if (player% 2! = 0):
  65. print («Вероятность игрока 1»)
  66. Mark = ‘X’
  67. else:
  68. print («Вероятность игрока 2»)
  69. Mark = ‘O’
  70. choice = int (input («Введите позицию между [1-9] где вы хотите отметить: «))
  71. if (CheckPosition (choice)):
  72. board [choice] = Mark
  73. player + = 1
  74. CheckWin ()
  75. os.system (‘cls’)
  76. DrawBoard ()
  77. if (Game == Draw):
  78. print («Game Draw»)
  79. elif (Game == Win):
  80. player- = 1
  81. if ( player% 2! = 0):
  82. print («Игрок 1 выиграл»)
  83. else:
  84. print («Игрок 2 выиграл»)

Вывод


.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *