Чайный сервиз — логическая игра-головоломка на поле по 3 клетки в две строки. На поле выставлены чайник, сахарница и три чашки. Цель игры: переставить чайник и сахарницу местами, а чашки пусть стоят так же, как в начале игры. Напишем программу игры чайный сервиз на Python с библиотекой tkinter.

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

Рис. 1

В этой программе игровое поле из Button объектов создадим по шаблону, разработанному в статье Игровое поле из Button:

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)

column = 5                          # столбцы
row = 5                             # строки
btn = []                            # список кнопок
img = []
files = ['red.png', 'yellow.png', 'gold.png',
         'green.png', 'emerald.png', 'cyan.png',
         'blue.png', 'pink.png','azure.png',
         'bronze.png', 'purple.png', 'scarlet.png',
         'steel.png', 'silver.png']

def play(n):                        # функция обработчик нажатия на кнопку
    shuffle(img)
    btn[n].config(image = img[0])

tk = Tk()
imgBL = PhotoImage(file="blank.png")
for i in files:
    img += [PhotoImage(file=i)]

for i in range(row):
    f = Frame()
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        btn += [Button(f, image=imgBL)]
        btn[-1].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[-1].config(command=lambda n=i*column+j:play(n))

mainloop()

Лист. 1.

Изменим количество кнопок (переменные column и row) и картинки. Строка imgBL = PhotoImage(file="blank.png") в этой программе нам не нужна.

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)

column = 3                          # столбцы
row = 2                             # строки
btn = []                            # список кнопок
img = []
files = ['tea.png','blank.png','sugar.png','cups.png','cup.png',]

def play(n):                        # функция обработчик нажатия на кнопку
    shuffle(img)
    btn[n].config(image = img[0])

tk = Tk()
for i in files:
    img += [PhotoImage(file=i)]

for i in range(row):
    f = Frame()
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        btn += [Button(f, image=img[i*column+j])]
        btn[-1].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[-1].config(command=lambda n=i*column+j:play(n))

mainloop()

Лист. 2.

Программа листинг 2 выполняется с ошибкой "IndexError: list index out of range".

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)

column = 3                          # столбцы
row = 2                             # строки
btn = []                            # список кнопок
img = []
files = ['tea.png','blank.png','sugar.png','cups.png','cup.png',]
playGround = [0,1,2,3,4,3]

def play(n):                        # функция обработчик нажатия на кнопку
    m = playGround.index(1)
    playGround[n], playGround[m] = playGround[m], playGround[n]
    btn[n].config(image = img[playGround[n]])
    btn[m].config(image = img[playGround[m]])

tk = Tk()
for i in files:
    img += [PhotoImage(file=i)]

for i in range(row):
    f = Frame()
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        btn += [Button(f, image=img[playGround[i*column+j]])]
        btn[-1].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[-1].config(command=lambda n=i*column+j:play(n))

mainloop()

Лист. 3.

#!/usr/bin/env python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# puzzle.py
# Copyleft (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank Sergey Polozkov for checking the code for hidden errors.
# I want to thank Sergey Polozkov for the idea of creating this puzzle.
# I want to thank all my students for the inspiration they give me.
#
# puzzle.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# puzzle.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
from random import shuffle          # перемешать список suffle(A)

column = 3                          # столбцы
row = 2                             # строки
btn = []                            # список кнопок
img = []
files = ['tea.png','blank.png','sugar.png','cups.png','cup.png',]
playGround = [0,1,2,3,4,3]

def play(n):                        # функция обработчик нажатия на кнопку
    m = playGround.index(1)
    if (abs(m - n) + abs(n//3 - m//3)) == 1 or abs(m - n) == 3:
        playGround[n], playGround[m] = playGround[m], playGround[n]
        btn[n].config(image = img[playGround[n]])
        btn[m].config(image = img[playGround[m]])

tk = Tk()
for i in files:
    img += [PhotoImage(file=i)]

for i in range(row):
    f = Frame()
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        btn += [Button(f, image=img[playGround[i*column+j]])]
        btn[-1].pack(expand=YES, fill=BOTH, side=LEFT)
        btn[-1].config(command=lambda n=i*column+j:play(n))

mainloop()

Лист. 4.