Tkinter python крестики нолики
Крестики-нолики — логическая игра между двумя противниками на квадратном поле 3 на 3 клетки или большего размера. Напишем программу игры крестики-нолики на Python с библиотекой tkinter.
Создадим поле из 9 кнопок для игры крестики-нолики.
from tkinter import * for i in range(9): Button().pack() mainloop()
Библиотека tkinter
В программе листинг 1, в первой строке мы импортируем все функции из библиотеки tkinter. Графическая библиотека tkinter входит в стандартный дистрибутив Python версии 3 и старше и служит для создания графического интерфейса программ на Pyton. В версии 2.7 имеется библиотека Tkinter с тем же функционалом.
Цикл for, функция range()
Ключевое слово for создаёт цикл, в котором переменная i последовательно принимает значения из диапазона range(9).
Функция range() создаёт диапазон значений. Параметрами функции range() могут быть границы диапазона и приращение (правая граница не включается в диапазон).
Цикл for создаётся с помощью ключевых слов for и in, определение цикла заканчивается двоеточием :. После двоеточия начинается тело цикла. Каждый оператор тела цикла, если он пишется с новой строки, должен иметь отступ слева. Для выделения блока операторов в python, (например, тела цикла) рекомендуется добавлять перед каждым оператором блока 4 пробела.
Цикл for i in range(9): выполняется 9 раз, при этом переменная i принимает значения от 0 до 9 с шагом 1. 0 включительно 9 исключительно. Так как мы указли только один параметр диапазона range(), диапазон создан с левой границей 0 и шагом 1 по умолчанию. 9 — правая граница диапазона.
Конструктор Button() метод pack()
В цикле for выполняется конструктор Button() с методом pack().
Конструктор Button() создаёт объект кнопка. Метод pack() отображает объект кнопку в окне программы. Окно программы, у нас создаётся библиотекой tkinter по умолчанию, как только мы создаём в программе визуальный объект (кнопку, например). Функция Button() выполняется в цикле 9 раз и наша программа, листинг 1, создаёт 9 кнопок в окне нашего приложения, см. рис. 1.
from tkinter import * for i in range(9): Button().pack(expand=YES, fill=BOTH) mainloop()
В программе листинг 2 в методе pack() мы добавили два параметра. Параметр expand со значением YES применяется для того, чтобы визуальный объект мог занять всё свободное пространство в контейнере. В нашем случае, кнопка (визуальный объект) размещается в окне программы (контейнер).
Свойство fill со значением BOTH позволяет визуальному объекту растягиваться в обоих направлениях, по X и по Y до размера контейнера.
from tkinter import * for i in range(9): Button().pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
В программе листинг 3 параметр side со значением LEFT прижимает визуальный объект влево при размещении в контейнере.
from tkinter import * for i in range(3): for j in range(3): Button().pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
Вложенные циклы
В программе листинг 4 мы, вместо одного цикла из 9 повторений сделали два вложенных цикла из 3х3 повторений. Программа всё так же создаёт 9 кнопок с теми же параметрами размещения, поэтому, внешне в окне программы ни чего не меняется.
from tkinter import * frm = [] for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): Button(frm[i]).pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
Списки, метод append(). Констуктор Frame()
В программе листинг 5 мы создали пустой список с именем frm. В цикле из трёх повторений в список frm методом append() добавляется 3 фрейма. Фрейм — это контейнер для других визуальных объектов. По умолчанию фрейм невидим и прозрачен. Создаёт фреймы конструктор Frame(). В нашей программе мы размещаем невидимые фреймы на экране растянутыми по горизонтали методом pack() с соответствующими параметрами.
В итоге, мы имеем список frm состоящий из трёх фреймов. К верхнему фрейму можно обратиться по имени frm[0], к среднему — по имени frm[1], к нижнему — frm[3].
Во внутреннем цикле for методом Button() с параметром frm[i] создаются кнопки. Первый параметр метода Button() указывает на родительский контейнер в котором должна быть размещены кнопка. Так как переменная i первые три повторения внутреннего цикла имеет значение 0, то первые три кнопки размещаются в верхнем фрейме. Ещё три кнопки размещаются в среднем фрейме и ещё три — в нижнем.
В дальнейшем у нас возникнет необходимость обращаться к кнопкам, как к объектам, по имени. Поэтому, в программе листинг 6 мы создали пустой список btn в который в цикле будет добавлено 9 кнопок.
from tkinter import * frm = []; btn = [] for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i])) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
В программе листинг 6 в цикле из 9 повторений в список btn методом append() добавляется 9 объектов класса Button (кнопоки). В списке btn все кнопки имеют индекс (номер) от 0 до 8 включительно. Чтобы разместить эти кнопки на экране методом pack(), к каждой кнопке мы должны обратиться по индексу. Индекс очередной кнопки мы вычисляем, используя параметры внешнего и внутреннего цикла, переменные i и j.
В остальном, программа листинг 6 не отличается от программы листинг 5.
from tkinter import * frm = []; btn = [] def play(n): btn[n].config(text=str(n)) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i])) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
Функция пользователя
В программе листинг 7 с помощью ключевого слова def мы создали функцию play(). Новые функции, созданные программистом в программе называют функциями пользователя. Новые функции, обычно, создают в начале программы после определения глобальных переменных, до их первого упоминания в коде программы.
В теле функции play() мы прописали метод config() применяемый к кнопке по которой кликнул игрок. Параметр text метода config() выводит на кнопку надпись. Функция str() превращает число в строку. Параметр n, передаваемый в функцию play() это номер кнопки по которой кликнул игрок.
Обработка событий
Функция play() будет зарегистрирована как обработчик события «клик мышью по кнопке». Обработчик события по умолчанию для кнопки можно зарегистрировать методом config(). Параметр command метода config() регистрирует обработчик события. Так как значением параметра command должно быть имя функции без скобок, мы для передачи параметра в функцию play в случае возникновения события, воспользовались lambda функцией.
Функция lambda()
Первый параметр lambda функции n вычисляется в процессе создания объекта кнопка, а второй параметр, указанный в lambda функции после двоеточия, передаётся для регистрации в качестве обработчика события. А в lambda функции мы указываем функцию play() с круглыми скобками и передаваемым параметром n. Причём, параметр n вячисляется на этапе создания кнопки и сохраняется в свойстве command как значение. То есть, функция play, как обработчик события будет вызвана с параметром номер кнопки, который был вычислен на этапе создания кнопки.
from tkinter import * frm = []; btn = []; who = True def play(n): global who btn[n].config(text= 'X' if who else 'O') who = not(who) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i])) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT) mainloop()
from tkinter import * frm = []; btn = []; who = True def play(n): global who btn[n].config(text= 'X' if who else 'O') who = not(who) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i], text=' ', font=('mono', 20, 'bold'), width=3, height=2)) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT, padx=1, pady=1) mainloop()
from tkinter import * frm = []; btn = []; who = True def play(n): global who btn[n].config(text= 'X' if who else 'O', state=DISABLED) who = not(who) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i], text=' ', font=('mono', 20, 'bold'), width=3, height=2)) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT, padx=1, pady=1) mainloop()
Часть 2. Думалка.
from tkinter import * frm = []; btn = []; who = True playArea = [] def play(n): global who btn[n].config(text= 'X' if who else 'O', state=DISABLED) playArea[n] = 1 if who else -1 who = not(who) print(playArea) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i], text=' ', font=('mono', 20, 'bold'), width=3, height=2)) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT, padx=1, pady=1) playArea.append(0) mainloop()
[1, 0, 0, 0, 0, 0, 0, 0, 0] [1, 0, 0, 0, 0, 0, 0, 0, -1] [1, 0, 0, 0, 1, 0, 0, 0, -1] [1, 0, 0, 0, 1, 0, -1, 0, -1] [1, 0, 0, 0, 1, 0, -1, 1, -1] [1, -1, 0, 0, 1, 0, -1, 1, -1] [1, -1, 0, 0, 1, 1, -1, 1, -1] [1, -1, 0, -1, 1, 1, -1, 1, -1] [1, -1, 1, -1, 1, 1, -1, 1, -1]
from tkinter import * frm = []; btn = []; who = True playArea = [] standings = [] # Турнирная таблица (положение) def play(n): global who btn[n].config(text= 'X' if who else 'O', state=DISABLED) playArea[n] = 1 if who else -1 standings[0] = playArea[0] + playArea[1] + playArea[2] standings[1] = playArea[3] + playArea[4] + playArea[5] standings[2] = playArea[6] + playArea[7] + playArea[8] standings[3] = playArea[0] + playArea[3] + playArea[6] standings[4] = playArea[1] + playArea[4] + playArea[7] standings[5] = playArea[2] + playArea[5] + playArea[8] standings[6] = playArea[0] + playArea[4] + playArea[8] standings[7] = playArea[2] + playArea[4] + playArea[6] print(n, standings[0:8]) who = not(who) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i], text=' ', font=('mono', 20, 'bold'), width=3, height=2)) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT, padx=1, pady=1) playArea.append(0) standings.append(0) mainloop()
0 [1, 0, 0, 1, 0, 0, 1, 0] 1 [0, 0, 0, 1, -1, 0, 1, 0] 2 [1, 0, 0, 1, -1, 1, 1, 1] 5 [1, -1, 0, 1, -1, 0, 1, 1] 4 [1, 0, 0, 1, 0, 0, 2, 2] 8 [1, 0, -1, 1, 0, -1, 1, 2] 7 [1, 0, 0, 1, 1, -1, 1, 2] 6 [1, 0, -1, 0, 1, -1, 1, 1] 3 [1, 1, -1, 1, 1, -1, 1, 1]
from tkinter import * frm = []; btn = []; who = True playArea = [] standings = [] # Турнирная таблица (положение) def play(n): global who btn[n].config(text= 'X' if who else 'O', state=DISABLED) playArea[n] = 1 if who else -1 standings[0] = playArea[0] + playArea[1] + playArea[2] standings[1] = playArea[3] + playArea[4] + playArea[5] standings[2] = playArea[6] + playArea[7] + playArea[8] standings[3] = playArea[0] + playArea[3] + playArea[6] standings[4] = playArea[1] + playArea[4] + playArea[7] standings[5] = playArea[2] + playArea[5] + playArea[8] standings[6] = playArea[0] + playArea[4] + playArea[8] standings[7] = playArea[2] + playArea[4] + playArea[6] print(n, standings[0:8]) for i in range(8): if standings[i] == 3: print('X win') elif standings[i] == -3: print('O win') who = not(who) for i in range(3): frm.append(Frame()) frm[i].pack(expand=YES, fill=BOTH) for j in range(3): btn.append(Button(frm[i], text=' ', font=('mono', 20, 'bold'), width=3, height=2)) btn[i*3+j].config(command=lambda n=i*3+j:play(n)) btn[i*3+j].pack(expand=YES, fill=BOTH, side=LEFT, padx=1, pady=1) playArea.append(0) standings.append(0) mainloop()
0 [1, 0, 0, 1, 0, 0, 1, 0] 1 [0, 0, 0, 1, -1, 0, 1, 0] 4 [0, 1, 0, 1, 0, 0, 2, 1] 2 [-1, 1, 0, 1, 0, -1, 2, 0] 8 [-1, 1, 1, 1, 0, 0, 3, 0] X win