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.