Крестики нолики python kivy

Пишем крестики-нолики на Python

Kivy — это открытая Python библиотека для быстрой разработки приложений. У нее много преимуществ, например, кросс-платформенность, открытость а также использование GPU для ускорения отрисовки графических интерфейсов.

Информацию об API вы можете найти тут.

Для начала работы нам потребуется библиотека kivy. Установить ее можно с помощью команды (Windows):

Либо с помощью команды (Linux, Python 3):

Импортируем необходимые нам элементы:

from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.gridlayout import GridLayout from kivy.uix.button import Button from kivy.config import Config

С помощью Config и функции set зададим параметры нашего окна:

Config.set("graphics", "resizable", "0") Config.set("graphics", "width", "300") Config.set("graphics", "height", "300")

Мы установили размер окна 300х300 и указали что окно нельзя перерастягивать.

Нам нужно, чтобы при каждом новом ходе крестик сменялся ноликом и наоборот. Для этого создадим класс нашего приложения, и назовем его MainApp . Оно должно наследоваться от класса kivy – App . Внутри класса создадим переменную self.switch , и определим ее в функции __init__ :

class MainApp(App): def __init__(self): self.switch = True super().__init__()

Строчка с super() нужна для того, чтобы инициализировать родительский класс App .

Внутри класса мы также объявим 3 функции: tic_tac_toe , restart и build :

def tic_tac_toe(self): pass def restart(self): pass def build(self): pass

Поговорим подробнее о каждой из них.

  • tic_tac_toe : функция, которая будет исполнять всю логику нашего приложения, с английского tic tac как раз и означает крестики-нолики
  • restart : функция, которую мы будем вызывать для того, чтобы перезапустить игру, по сути сбросив все значения кнопок и переменных до начального состояния
  • build : важная функция, она определена в самом App , но ее поведение мы должны «перегрузить»

Начнем как раз с функции build .

def build(self): self.title = "Крестики-нолики" root = BoxLayout(orientation="vertical", padding=5) grid = GridLayout(cols=3)

self.title это название нашего окна, далее создадим объект BoxLayout , он будет являться своеобразным контейнером для всех наших кнопок. Также создадим переменную GridLayout , и укажем число колонок = 3. На рисунке ниже ее область будет показана красным цветом. После того, как отрисуем область сетки, добавим внизу кнопочку Restart (показана синим цветом).

После этого, в цикле мы добавим в лист 9 объектов класса Button . Каждый такой объект имеет цвет, размер шрифта и другие переменные. При нажатии на такую кнопку вызывается метод tic_tac_toe , о котором мы поговорим чуть позднее. В конце цикла не забываем добавить полученные в ходе тела цикла кнопки в наш лист self.buttons , кроме того, добавляем новый виджет в grid :

for _ in range(9): button = Button( color = [0,0,0,1], font_size = 24, disabled = False, on_press = self.tic_tac_toe ) self.buttons.append(button) grid.add_widget(button)

Также добавим виджет для кнопки Restart:

root.add_widget( Button( text = "Restart", size_hint = [1,.1], on_press = self.restart ) )

Весь код функции build целиком:

def build(self): self.title = "Крестики-нолики" root = BoxLayout(orientation="vertical", padding=5) grid = GridLayout(cols=3) self.buttons = [] for _ in range(9): button = Button( color = [0,0,0,1], font_size = 24, disabled = False, on_press = self.tic_tac_toe ) self.buttons.append(button) grid.add_widget(button) root.add_widget(grid) root.add_widget( Button( text = "Restart", size_hint = [1,.1], on_press = self.restart ) ) return root

Поскольку мы добавили кнопку Restart, давайте поговорим об ее функционале. Добавим в функцию restart следующий код:

def restart(self, arg): self.switch = True for button in self.buttons: button.color = [0,0,0,1] button.text = "" button.disabled = False

Переменная switch = True показывает, что ход снова возвращается к крестикам, как и было указано в начале игры. Далее мы проходимся в цикле по всем кнопкам, возвращая им цвет по умолчанию и стирая текст. Модификатор disabled показывает, что теперь вы снова можете нажать на кнопку.

Но вернемся к функции tic_tac_toe . Для начала укажем снова глобальную переменную switch . Как вы помните, она переключается в обратное положение каждый раз после нажатия кнопки, чем символизирует переключение хода на другого игрока. В этой функции аргумент arg будет как раз являться нашим конкретным button .

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

def tic_tac_toe(self, arg): arg.disabled = True

Теперь проверим в каком положении стоит наш self.switch , и в зависимости от этого, определим переменную arg.text крестиком либо ноликом:

def tic_tac_toe(self, arg): arg.disabled = True arg.text = 'X' if self.switch else 'O'

Фактически, выражение ‘X’ if self.switch else ‘O’ означает ‘X’ в случае если self.switch = True и ‘O’ в случае если self.switch = False .

После этого, разумеется, мы должны переключить ход:

self.switch = not self.switch

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

coordinate = ( (0,1,2),(3,4,5),(6,7,8), # по оси X (0,3,6),(1,4,7),(2,5,8), # по оси Y (0,4,8),(2,4,6), # по диагонали D )

Также зададим и возможные вектора самих нажатых кнопок (в них будет храниться буквы ‘X’ либо ‘O’ ). Легче всего это сделать, написав короткую лямбда-функцию, которая будет возвращать список букв для каждого набора координат:

vector = lambda item: [self.buttons[x].text for x in item]

Такой объект является анонимной функцией, при выполнении которой возвратится список в котором будут храниться буквы. Если в таком списке все 3 буквы одинаковые, это означает выигрыш!

Определим переменную win = False , а также цвет кнопок в результате выигрыша:

win = False color = [0,1,0,1] # Зеленый

Теперь напишем цикл, который будет определять победную комбинацию нажатых кнопок. В переменной coordinate есть 8 комбинаций с победными сочетаниями кнопок. Пройдемся по ним в цикле:

for item in coordinate: if vector(item).count('X') == 3\\ or vector(item).count('O') == 3: win = True for i in item: self.buttons[i].color = color break

Если в таком векторе функция count посчитает 3 раза буквы ‘X’ либо ‘O’ , значит игрок победил, в таком случае окрашиваем победную комбинацию кнопок в зеленый цвет.

Также необходимо залочить все кнопки в случае победы:

if win: for button in self.buttons: button.disabled = True

Внимательный читатель мог заметить, что переменная win в принципе и не нужна, а последний цикл можно переместить в цикл после перекрашивания цвета кнопок в зеленый. Полный код функции tic_tac_toe после рефакторинга:

def tic_tac_toe(self, arg): arg.disabled = True arg.text = 'X' if self.switch else 'O' self.switch = not self.switch coordinate = ( (0,1,2),(3,4,5),(6,7,8), # X (0,3,6),(1,4,7),(2,5,8), # Y (0,4,8),(2,4,6), # D ) vector = lambda item: [self.buttons[x].text for x in item] color = [0, 1, 0, 1] for item in coordinate: if vector(item).count('X') == 3 \\ or vector(item).count('O') == 3: for i in item: self.buttons[i].color = color for button in self.buttons: button.disabled = True break

Источник

Читайте также:  Ширина блока
Оцените статью