Pyzzle 15, игра известная в нашей стране, как «Пятнашки». «Пятнашки» – это логическая игра-головоломка. Цель игры – упорядочить пронумерованные плитки на игровом поле размером 4Х4 клетки.
Пишем компьютерную версию игры на языке программирования Python.
from tkinter import * # импортируем всё из tkinter
from random import shuffle # импортируем shuffle для перемешивания списка
cols = rows = 4 # размеры игрового поля
playground = [] # список для объектов StringVar
space = rows * cols - 1 # номер пустой клетки. Изначально это последняя клетка
def start(event):
"""
Запускает новую игру: делает множество случайных перемешиваний.
Обработчик события <space> нажатие пробела.
"""
global space # номер пустой клетки
for i in range(1000):
N = [] # для возможных ходов из соседних с пробелом клеток
for n in (space+1, space-1, space-cols, space+cols):
if 0 <= n < rows * cols: # если номер клетки в пределах поля
N.append(n)
shuffle(N) # перемешиваем список возможных ходов
play(N[0]) # делаем ход
def play(n):
"""
Функция меняет местами пустую клетку и выбранную, если ход допустим.
Обработчик события клик по кнопке.
"""
global space # номер пустой клетки
# Проверяем, является ли ход допустимым
if n in (space + 1, space - 1) and \
n // cols == space // cols or \
n in (space - cols, space + cols):
playground[space].set(playground[n].get()) # меняем текст на кнопке
playground[n].set(" ") # теперь эта кнопка пустая
space = n # обновляем номер пустой клетки
tk = Tk() # Создаём главное окно
tk.geometry('600x600')
tk.title("Space - START GAME")
tk.bind('<space>', start) # Привязываем пробел к функции start
for n in range(cols * rows): # Создаём поле из кнопок
# Для каждой клетки создаём StringVar с начальным текстом (число n+1)
playground.append(StringVar(value=str(n + 1)))
if n % cols == 0: # Каждый ряд начинаем с нового фрейма
f = Frame()
f.pack(expand=YES, fill=BOTH)
btn = Button(f, textvariable=playground[n],
command= lambda n=n: play(n)) # Создаём кнопку
btn.pack(expand=YES, fill=BOTH, side=LEFT)
btn.config(font=('mono', 36, 'italic'), width=3, height=2) # Настраиваем внешний вид
playground[cols * rows - 1].set(" ") # Последнюю клетку делаем пустой
mainloop() # Запускаем главный цикл обработки событий
Лист. 1. С использованием списка объектов StringVar.
from tkinter import * # импортируем всё из tkinter
from random import shuffle # импортируем shuffle для перемешивания списка
cols = rows = 4 # размеры игрового поля
playground = [] # список для объектов Button
space = rows * cols - 1 # номер пустой клетки. Изначально это последняя клетка
def start(event):
"""
Запускает новую игру: делает множество случайных перемешиваний.
Обработчик события <space> нажатие пробела.
"""
global space # номер пустой клетки
for i in range(1000):
N = [] # для возможных ходов из соседних с пробелом клеток
for n in (space+1, space-1, space-cols, space+cols):
if 0 <= n < rows * cols: # если номер клетки в пределах поля
N.append(n)
shuffle(N) # перемешиваем список возможных ходов
play(N[0]) # делаем ход
def play(n):
"""
Функция меняет местами пустую клетку и выбранную, если ход допустим.
Обработчик события клик по кнопке.
"""
global space # номер пустой клетки
# Проверяем, является ли ход допустимым
if n in (space + 1, space - 1) and \
n // cols == space // cols or \
n in (space - cols, space + cols):
playground[space].config(text=playground[n].cget('text')) # меняем текст на кнопке
playground[n].config(text=" ") # теперь эта кнопка пустая
space = n # обновляем номер пустой клетки
tk = Tk() # Создаём главное окно
tk.geometry('600x600')
tk.title("Space - START GAME")
tk.bind('<space>', start) # Привязываем пробел к функции start
for n in range(cols * rows): # Создаём поле из кнопок
if n % cols == 0: # Каждый ряд начинаем с нового фрейма
f = Frame()
f.pack(expand=YES, fill=BOTH)
playground.append(Button(f, text=n+1, command=lambda n=n: play(n))) # Создаём кнопку
playground[n].pack(expand=YES, fill=BOTH, side=LEFT)
playground[n].config(font=('mono', 36, 'italic'), width=3, height=2) # Настраиваем внешний вид
playground[n].config(text=" ") # Последнюю клетку делаем пустой
mainloop() # Запускаем главный цикл обработки событий
Лист. 2. С использованием списка объектов Button.
from tkinter import * # импортируем всё из tkinter
from random import shuffle # импортируем shuffle для перемешивания списка
import types # для динамического добавления метода show к каждой кнопке
cols = rows = 4 # размеры игрового поля
playground = [] # список для чисел и пробела, используемых на кнопках
def start(event):
"""
Запускает новую игру: делает множество случайных перемешиваний.
Обработчик события <space> нажатие пробела.
"""
for i in range(1000):
N = [] # для возможных ходов из соседних с пробелом клеток
space = playground.index(" ") # номер пустой клетки
for n in (space+1, space-1, space-cols, space+cols):
if 0 <= n < rows * cols: # если номер клетки в пределах поля
N.append(n)
shuffle(N) # перемешиваем список возможных ходов
play(N[0]) # делаем ход
def play(n):
"""
Функция меняет местами пустую клетку и выбранную, если ход допустим.
Обработчик события клик по кнопке.
"""
space = playground.index(" ") # номер пустой клетки
# Проверяем, является ли ход допустимым
if n in (space + 1, space - 1) and \
n // cols == space // cols or \
n in (space - cols, space + cols):
playground[space] = playground[n] # меняем текст
playground[n] = " " # теперь эта кнопка пустая
def show(self):
"""
Метод, добавляемый каждой кнопке. Обновляет текст на кнопке
в соответствии со значением в playground.
"""
self.config(text = playground[self.n])
self.after(400, self.show) # повторяем обновление каждые 400 мс
tk = Tk() # Создаём главное окно
tk.geometry('600x600')
tk.title("Space - START GAME")
tk.bind('<space>', start) # Привязываем пробел к функции start
for n in range(cols * rows): # Создаём поле из кнопок
if n % cols == 0: # Каждый ряд начинаем с нового фрейма
f = Frame()
f.pack(expand=YES, fill=BOTH)
playground.append(str(n+1)) # наполняем список числами
btn = Button(f, command=lambda n=n: play(n)) # Создаём кнопку
btn.pack(expand=YES, fill=BOTH, side=LEFT)
btn.config(font=('mono', 36, 'italic'), width=3, height=2) # Настраиваем внешний вид
btn.n = n # сохраняем номер клетки в атрибуте кнопки
btn.show = types.MethodType(show, btn) # добавляем метод show() к каждой кнопке
btn.show() # запускаем бесконечное обновление текста кнопки
playground[n] = " " # Последняя клетка будет пустой
mainloop() # Запускаем главный цикл обработки событий
Лист. 3. С использованием метода after.