Color Lines («Цветные линии», сокращённо Lines) — логическая компьютерная игра, разработанная Олегом Дёминым, и художниками Геннадием Денисовым и Игорем Ивкиным и изданная российской компанией Gamos в 1992 году.

Правила игры

Жанр игры —  головоломка. Игра рассчитана на одного игрока. Цель игры — набрать максимальное число очков. С каждым ходом компьютер вносит изменения на игровом поле с усложнением игровой ситуации и подсчитывает количество набранных игроком очков. 

Игра Lines 98 происходит на поле размером 9 на 9 клеток. В каждой клетке может находиться один шарик. В игре участвуют шарики одного из 8-ми цветов. За один ход игрок может переместить один из шариков на поле в пустую клетку. После каждого хода на свободных клетках игрового поля появляются, в случайном порядке, 3 новых шарика. Цвет новых шариков, так же, выбирается случайным образом. На поле, из шариков одного цвета, нужно составить цветную линию, состоящую из 5 или большего количества шариков одного цвета. Засчитываются линии построенные  по горизонтали, вертикали или диагонали. Если у шарика, выбранного игроком, на поле нет свободного пути к пустой клетке (цели), то перемещение шарика не происходит. То есть, компьютер должен найти непрерывный путь из пустых клеток, по которому должен пройти шарик, совершая движение из клетки в  соседнюю клетку только  по горизонтали или по вертикали.

Если после хода игрока или выпадания новых шариков появляется линия одного цвета длиной 5 или более шаров, то шары из линии уничтожается, а игроку будут начислены очки. Количество очков разное в зависимости от количества убираемых шаров. (10 очков за 5 шаров, 12 очков за 6 шаров, 18 очков за 7, 28 очков за 8, 42 очка за 9) Если шарики были убраны, то появление новых трех шариков откладывается на один ход. Цель игры - набрать больше всех очков, совершив при это максимальное количество ходов. Сверху над полем можно увидеть цвета новых шариков, которые будут выставлены после хода игрока. Для перемещение шарика нужно нажать на нем левой клавишей мыши, шар начнет прыгать, затем кликнуть на клетке, куда следует его переместить. Если вдруг шарик переместить не удаётся, будет выведено сообщение.

Цели

1. Цель получить практический опыт программирования на языке Python.

2. Получить опыт применения:

  • библиотек tkinter и random,
  • if
    • else
    • elif
  • множественного присваивания
  • укерк

Задачи

Создание игры в стиле Lines 98.

Игровое поле

В процессе написания программы нам предстоит создать игровое поле 9х9 клеток.

В игре участвуют шарики одного из 8-ми цветов. У нас имеются изображения шариков более 10 цветов. Пусть, в начале игры, шарики восьми цветов случайным образом отбираются из всех имеющихся в наличии изображений. 

Рис. 1. Изображения шариков в png формате.

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

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']

C = 8                               # Количество цветов
color = [i for i in range(len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки
print(color)

Лист. 1. Библиотеки, глобальные переменные и константы.

[13, 3, 8, 4, 5, 7, 12, 1]

Вывод программы лист. 1.

В программе лист. 1 подключаем графическую библиотеку tkinter и функцию shuffle из библиотеки random. 

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

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']

C = 8                               # Количкство цветов
color = [i for i in range(len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()

mainloop()

Лист. 2.

Рис. 2.

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

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']

C = 8                               # Количкство цветов
color = [i for i in range(len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

mainloop()

Лист. 3.

Рис. 3.

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

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']

C = 8                               # Количкство цветов
color = [i for i in range(len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    cnv.create_image(200, 300, image=img[7], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()
mainloop()

Лист. 4.

Рис. 4.

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

files = ['red.png','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']

C = 8                               # Количкство цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    print(color)
    shuffle(color)
    print(color)
    for i in range(3):
        playground[i] = color[i]
    print(playground)
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.create_image(40, 40, image=img[playground[0]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()
mainloop()

Лист. 5.

[5, 3, 11, 12, 13, 4, 1, 7]
[12, 11, 1, 5, 4, 3, 7, 13]
[12, 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

ыпар

Исправлена строка color = [i for i in range(1, len(files))]

В списке files продублировано имя файла первого шарика.

sdggh

Рис. 5

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

files = ['red.png','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']

C = 8                               # Количкство цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    shuffle(color)
    pg0 = []
    for i in range(N*N):
        if playground[i] == 0:
            pg0 += [i]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    print(playground)
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.create_image(40, 40, image=img[playground[0]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()
step()
step()
mainloop()

Лист. 6.

[0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 14, 14, 0, 0, 3, 0, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

dfh

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

files = ['red.png','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']

C = 8                               # Количкство цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    print(playground)
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.create_image(40, 40, image=img[playground[0]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()
step()
step()
mainloop()

Лист. 7.

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 7, 0, 0, 0, 0, 0, 0]
[4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 12, 7, 0, 0, 0, 0, 0, 0]
[4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 7, 0, 0, 0, 0, 9, 0, 0, 0, 12, 7, 0, 0, 0, 0, 0, 0]

dfh

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()
step()
step()
mainloop()

Лист. 8.

Рис. 6.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

for i in range(100): step()

mainloop()

Лист. 9.

Рис. 7.

Ходилка

еркр

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def ifplay(event):
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    print(x,y)

def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', ifplay)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], width=1)

step()

mainloop()

Лист. 10.

45 44
4 4
718 712
358 353

i

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def ifplay(event):
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]
    print(num, idb)

def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', ifplay)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 11.

10 85
30 87
14 86
42 89
35 88
70 90
0 1
80 81

ffb

Рис. 8.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def ifplay(event):
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика по мышью
    if idb > N*N:
        print(num, idb)
        
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', ifplay)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 12

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика по мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    pass

def moveEnd(event):                 # Конец движения
    pass
      
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 13.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика по мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")
      
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 14.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        pass
    else:
        draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")
      
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 15.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")
      
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]
    draw()

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
step()

mainloop()

Лист. 16.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая и
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
        step()
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")
      
def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step()
draw()

mainloop()

Лист. 17.

Думалка

еркр

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая и
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
        lines_del(*think(num2))
        step(False)
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def think(n):                       # Найти линии
    x = []
    y = []
    w = []
    z = []
    return [x, y, w, z]

def lines_del(a,b,c,d):                    # удалить линии
    return True

def step(sw):                         # Ход компьютера
    if sw or playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step(False)
draw()

mainloop()

Лист. 18.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая и
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
        lines_del(think(num2))
        step(False)
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def think(n):                       # Найти линии
    x = lines(n, [n-1, (n//N)*N-1, -1]) + lines(n, [n, (n//N+1)*N])
    y = lines(n, [n-N, -1, -N]) + lines(n, [n, N*N, N])
    w = lines(n, [n, N*N if n//N >= n%N else n+(N-n%N)*(N+1), N+1])
    w += lines(n, [n-N-1, -1 if n//N < n%N else n-n%N*(N+1)-1, -N-1])
    z = lines(n, [n-N+1, 0 if n%N < N-n//N else n-(N-n%N)*(N-1), -N+1])
    z += lines(n, [n, N*N if N-n//N <= n%N else n+(n%N)*(N-1)+1, N-1])
    return [x, y, w, z]

def lines(n, p):                    # Поиск смежных шариков
    x = []
    for i in range(*p):
        if playground[n] == playground[i]:
            x += [i]
        else: break
    return x

def lines_del(l):                    # удалить линии
    print(l)
    return True

def step(sw):                         # Ход компьютера
    if sw or playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step(False)
draw()

mainloop()

Лист. 19.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая и
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
        lines_del(think(num2))
        step(False)
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def think(n):                       # Найти линии
    x = lines(n, [n-1, (n//N)*N-1, -1]) + lines(n, [n, (n//N+1)*N])
    y = lines(n, [n-N, -1, -N]) + lines(n, [n, N*N, N])
    w = lines(n, [n, N*N if n//N >= n%N else n+(N-n%N)*(N+1), N+1])
    w += lines(n, [n-N-1, -1 if n//N < n%N else n-n%N*(N+1)-1, -N-1])
    z = lines(n, [n-N+1, 0 if n%N < N-n//N else n-(N-n%N)*(N-1), -N+1])
    z += lines(n, [n, N*N if N-n//N <= n%N else n+(n%N)*(N-1)+1, N-1])
    return [x, y, w, z]

def lines(n, p):                    # Поиск смежных шариков
    x = []
    for i in range(*p):
        if playground[n] == playground[i]:
            x += [i]
        else: break
    return x

def lines_del(l):                    # удалить линии
    result = False
    for a in l:
        if len(a) >= 5:
            result = True
            for i in a:
                playground[i] = 0
    return result

def step(sw):                         # Ход компьютера
    if sw or playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step(False)
draw()

mainloop()

Лист. 20.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая и
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2], playground[num] = playground[num], 0
        step(lines_del(think(num2)))
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def think(n):                       # Найти линии
    x = lines(n, [n-1, (n//N)*N-1, -1]) + lines(n, [n, (n//N+1)*N])
    y = lines(n, [n-N, -1, -N]) + lines(n, [n, N*N, N])
    w = lines(n, [n, N*N if n//N >= n%N else n+(N-n%N)*(N+1), N+1])
    w += lines(n, [n-N-1, -1 if n//N < n%N else n-n%N*(N+1)-1, -N-1])
    z = lines(n, [n-N+1, 0 if n%N < N-n//N else n-(N-n%N)*(N-1), -N+1])
    z += lines(n, [n, N*N if N-n//N <= n%N else n+(n%N)*(N-1)+1, N-1])
    return [x, y, w, z]

def lines(n, p):                    # Поиск смежных шариков
    x = []
    for i in range(*p):
        if playground[n] == playground[i]:
            x += [i]
        else: break
    return x

def lines_del(l):                    # удалить линии
    result = False
    for a in l:
        if len(a) >= 5:
            result = True
            for i in a:
                playground[i] = 0
    return result

def step(sw):                         # Ход компьютера
    if sw or playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step(False)
draw()

mainloop()

Лист. 21.

egerg

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

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']

color = [3, 4, 5, 8, 9, 10, 11, 12]  # Цвет в игре
melange = [i for i in range(len(color))]    # для перемешивания цветов
img = []                            # Список шариков, как объектов
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки (px)

def ifplay(event):                  # Разрешение движения
    if 0 not in playground: return
    global idb, num
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N             # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]
    if idb > IBM:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", play)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def play(event):
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N    # Целевая клетка
    if (playground[num2] == 0 and                   # Если целевая клетка пустая
        x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N): # Если курсор в пределах поля
        playground[num2] = playground[num]
        playground[num] = 0
        think(num2)
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def think(n):                       # Найти и удалить линии
    x = lines(n, [n-1, (n//N)*N-1, -1]) + lines(n, [n, (n//N+1)*N])
    y = lines(n, [n-N, -1, -N]) + lines(n, [n, N*N, N])
    w = lines(n, [n, N*N if n//N >= n%N else n+(N-n%N)*(N+1), N+1])
    w += lines(n, [n-N-1, -1 if n//N < n%N else n-n%N*(N+1)-1, -N-1])
    z = lines(n, [n-N+1, 0 if n%N < N-n//N else n-(N-n%N)*(N-1), -N+1])
    z += lines(n, [n, N*N if N-n//N <= n%N else n+(n%N)*(N-1)+1, N-1])
    #print(x, y, w, z)
    if not (clear(x) + clear(y) + clear(w) + clear(z)):  # Ленивый or не работает
        step()

def lines(n, p):                    # Поиск смежных шариков
    x = []
    for i in range(*p):
        if playground[n] == playground[i]:
            x += [i]
        else: break
    return x

def clear(a):                       # Удаление смежных шариков
    if len(a) >= 5:
        for i in a:
            playground[i] = 0
        draw()
        return True
    return False

def step():                         # Ход компьютера
    if playground.count(0)<3: return
    shuffle(melange)
    pg0 = []
    for i in range(N*N):
        if playground[i] == 0:
            pg0 += [i]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[melange[i]]
    draw()

def draw():
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], anchor=CENTER, tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N)       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', ifplay)
img += [PhotoImage(file=fi) for fi in files]    # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE,
                    fill=colores[0], outline=colores[1], width=1)
        
cnv.create_image(1, 1, image=img[0], anchor=CENTER, tag='allBalls')
IBM = cnv.find_overlapping(0, 0, 2, 2)[-1]      # Id Ball Min Наименьший номер для шариков
cnv.delete('allBalls')
step()
mainloop()

Лист. 22.

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

files = ['red.png','red.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']

C = 8                               # Количество цветов
color = [i for i in range(1, len(files))]
shuffle(color)
color = color[:C]                   # Цвет в игре
colores = ['#998', '#ccd']          # Цвета поля
N = 9                               # Ширина и высота игрового поля (клеток)
playground = [0] * N * N            # Игровое поле
SIZE = 80                           # Размер клетки

def play(event):
    global idb, num
    if 0 not in playground: return  # Игрок кликнул мышью
    x = event.x
    y = event.y
    num = x // SIZE + y // SIZE * N # Исходная клетка
    idb = cnv.find_overlapping(x, y, x+1, y+1)[-1]      # id шарика под мышью
    if idb > N*N:
        cnv.tkraise(idb)            # Поднять шарик на верхний слой
        cnv.bind("<B1-Motion>", move)           # Начать движение
        cnv.bind("<B1-ButtonRelease>", moveEnd) # Конец движения

def move(event):                    # движение
    x = int(event.x-cnv.coords(idb)[0])
    y = int(event.y-cnv.coords(idb)[1])
    cnv.move(idb, x, y)

def moveEnd(event):                 # Конец движения
    x = event.x
    y = event.y
    num2 = x // SIZE + y // SIZE * N                    # Целевая клетка
    if (x>=0 and x<=SIZE*N and y>=0 and y<=SIZE*N       # Если курсор в пределах поля
        and playground[num2] == 0 and                   # Если целевая клетка пустая
        path(num, num2, playground.copy())):            # Если есть путь
        playground[num2], playground[num] = playground[num], 0
        step(lines_del(think(num2)))
    draw()
    cnv.unbind("<B1-Motion>")
    cnv.unbind("<B1-ButtonRelease>")

def path(n1, n2, a):                # Поиск пути
    a[n1] = -1
    for i in [j for j in (n1-1, n1+1) if j//N == n1//N] + [j for j in (n1-N, n1+N) if j>=0 and j<N*N]:
        if a[i] == 0:
            path(i, n2, a)
    if a[n2] == -1:
        return True
    return False

def think(n):                       # Найти линии
    x = lines(n, [n-1, (n//N)*N-1, -1]) + lines(n, [n, (n//N+1)*N])
    y = lines(n, [n-N, -1, -N]) + lines(n, [n, N*N, N])
    w = lines(n, [n, N*N if n//N >= n%N else n+(N-n%N)*(N+1), N+1])
    w += lines(n, [n-N-1, -1 if n//N < n%N else n-n%N*(N+1)-1, -N-1])
    z = lines(n, [n-N+1, 0 if n%N < N-n//N else n-(N-n%N)*(N-1), -N+1])
    z += lines(n, [n, N*N if N-n//N <= n%N else n+(n%N)*(N-1)+1, N-1])
    return [x, y, w, z]

def lines(n, p):                    # Поиск смежных шариков
    x = []
    for i in range(*p):
        if playground[n] == playground[i]:
            x += [i]
        else: break
    return x

def lines_del(l):                    # удалить линии
    result = False
    for a in l:
        if len(a) >= 5:
            result = True
            for i in a:
                playground[i] = 0
    return result

def step(sw):                         # Ход компьютера
    if sw or playground.count(0)<3: return
    shuffle(color)
    pg0 = [i for i in range(N*N) if playground[i] == 0]
    shuffle(pg0)
    for i in range(3):
        playground[pg0[i]] = color[i]

def draw():                         # Перерисовать игровое поле
    cnv.delete('allBalls')
    for i in range(N*N):
        if playground[i] != 0:
            x = (i % N) * SIZE + SIZE / 2
            y = (i // N) * SIZE + SIZE / 2
            cnv.create_image(x, y, image=img[playground[i]], tag='allBalls')

cnv = Canvas(width=SIZE*N, height=SIZE*N, bg=colores[0])       # Объект класса Canvas
cnv.pack()
cnv.bind('<Button-1>', play)
img = [PhotoImage(file=fi) for fi in files]         # Объекты класса PhotoImage

for y in range(N):                  # Отрисовка поля
    for x in range(N):
        cnv.create_rectangle(x*SIZE, y*SIZE,(x+1)*SIZE,
            (y+1)*SIZE, outline=colores[1], fill=colores[0], width=1)

step(False)
draw()

mainloop()

Лист. 23.

Дополнительные источники:

https://youtu.be/4iDv8Zu8L3I?si=H5iRl2JJBnWrk9p6

tkinter-docs Canvas