Судоку — головоломка с числами, впервые появилась в 1979 г. В 2012 году доказано, что однозначно решаемые задания игры судоку должны иметь более 16 подсказок.
Игровое поле для игры судоку представляет собой квадрат размером 9×9 клеток, по 9 клеток сгруппировано в квадраты 3х3 клетки. Таким образом, всё игровое поле состоит из 81 клетки. В них уже в начале игры стоят некоторые числа (от 1 до 9), называемые подсказками. От игрока требуется заполнить свободные клетки цифрами от 1 до 9 так, чтобы в каждой строке, в каждом столбце и в каждом малом квадрате 3×3 каждая цифра встречалась только один раз.
Напишем программу, формирующую игровое поле для судоку на экране. Для этого, с использованием библиотеки tkinter, создадим:
- 3 строки из фреймов (Frame),
- в каждую из этих строк поместим по 3 блока-фрейма для кнопок, всего 9 блоков,
- в каждый блок поместим по 9 клеток-кнопок (Button).
К изложенному плану работ есть существенное замечание. Чтобы клетки-кнопки нумеровались на игровом поле по порядку, в первой строке от 0 до 8, во второй строке от 9 до 17 и т.д., кнопки в блоках необходимо располагать по одной строчке (по три кнопки) последовательно в строке из трёх блоков.
Рис. 1. Порядок размещения клеток-кнопок на игровом поле судоку.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=n)
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
mainloop() # Главный цикл программы
Лист. 1. Программа, разбивающая поле для игры на 3х3 большие клетки и каждую из этих клеток на 3х3 клеточки.
Рис. 2. Результат работы программы листинг 1. Игровое поле с пронумерованными клетками.
Стивен Скиена в книге "Алгоритмы Руководство по разработке" на странице 259 приводит две таблицы, начальное состояние на игровом поле в игре судоку и решение для этого начального условия игры.
Перенесём пример из книги С. Скиены в нашу программу. В начале создадим список цифр из таблицы с решением игры.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
mainloop() # Главный цикл программы
Лист. 2. Список skiena содержит решение для игры судоку.
В программе листинг 2, в функции play, реализована возможность вывести на игровое поле значения из списка skiena.
Рис. 3. Решение на игровом поле, построенное по таблицам из книги Стивена Скиена "Алгоритмы Руководство по разработке", стр. 259.
На рис. 3. мы видим результат работы программы листинг 2. Последовательно, щёлкая левой кнопкой мыши мы вывели на кнопки значения из списка skiena.
В начале игры, в задании игры судоку, приведённом в книге Стивена Скиена, открыто всего 17 цифр из таблицы с решением, см. рис. 2. Это первый, и пока единственный, найденный вариант из 17 цифр - подсказок, имеющий однозначное решение.
Создадим список подсказок и выведем на игровое поле только подсказки, таким образом, мы получим на игровом поле начальное состояние игры.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
mainloop() # Главный цикл программы
Лист. 3. Программа, генерирующая игровое поле с подсказками для игры судоку.
Рис. 4. Состояние игрового поля в начале игры, сгенерированное программой листинг 3.
Игра судоку может существовать с множеством начальных условий, а это даёт возможность многим авторам придумывать свои судоку. Единственное правило, которое должно соблюдаться - это то, что судоку должны иметь решение и оно должно быть единственным.
В нашей программе судоку мы воспользовались таблицами из книги Стивена Скиена "Алгоритмы Руководство по разработке" приведёнными на странице 259. Но это один вариант игры. Теперь нам предстоит написать генератор различных вариантов судоку. Варианты игры будем генерировать следующими случайными перестановками:
- замена каждой цифры на другую, случайно выбранную,
- перестановка столбцов в группах из трёх столбцов,
- перестановка групп столбцов,
- перестановка строк в группах из трёх строк,
- перестановка групп строк.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init(skiena, playground):
return skiena, playground
skiena, playground = init(skiena, playground)
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
mainloop() # Главный цикл программы
Лист. 4. Добавлена функция init, которая будет выполнять все запланированные нами преобразования списков skiena и playground.
Начнём с замены цифр в случайном порядке.
Создадим список цифр от 1 до 9 и перемешаем его. Присвоим этому перемешанному списку имя rnd от слова random (случайный). Пусть теперь порядок цифр в списке rnd будет определять способ замены цифр в списке skiena.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init(skiena, playground):
rnd = list('123456789')
shuffle(rnd)
print(rnd)
for i in range(0, 8, 2): # замена случайно выбранных цифр на другие случайно выбранные
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
return skiena, playground
skiena, playground = init(skiena, playground)
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
mainloop() # Главный цикл программы
Лист. 5. В функции init реализована замена одних цифр другими по случайному закону.
['1', '8', '6', '4', '7', '2', '5', '3', '9']
Лист. 6. Результат работы функции print в функции init.
В листинге 6 напечатан перемешанный список rnd. В функции init в цикле for попарно будут использованы элементы этого списка.
При первом проходе цикла for, когда переменная цикла i = 0, в списке skiena все цифры 1 будут заменены на цифру 8, а все цифры 8 заменяются на цифру 1. На втором проходе цикла for в функции init будут использованы цифры 6 и 4 из списка rnd. И так будет происходить далее до конца списка rnd.
Рис. 5. Новое судоку, полученное из предложенного С. Скиена путём замены цифр на другие по случайному закону.
В программе листинг 5 в начале программы созданы две глобальные переменные skiena и playground. Эти переменные в дальнейшем используются 1 раз, для передачи значений списков в функцию init. Дальнейшее их использование в программе не предусмотрено, далее используются им одноимённые переменные с другими значениями. Будет целесообразно переместить эти переменные в тело функции init.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
mainloop() # Главный цикл программы
Лист. 7. Немного упорядочен код.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
#rnd = list('123456789')
#shuffle(rnd)
#for i in range(0, 8, 2):
# skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
# перестановка групп колонок
skiena = [(int(i)) for i in list(skiena)]
rnd = [0, 1, 2]
shuffle(rnd)
back_skiena = skiena.copy()
back_playground = playground.copy()
for r in range(9): # цикл по строкам в таблице
for g in range(3): # цикл по группам колонок
for c in range(3): # цикл по столбцам в группе столбцов
skiena[g*3+c+r*9] = back_skiena[rnd[g]*3+c+r*9]
playground[g*3+c+r*9] = back_playground[rnd[g]*3+c+r*9]
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
for n in range(81):
play(n)
mainloop() # Главный цикл программы
Лист. 8. В функцию init добавлена перестановка групп колонок по случайному закону.
Рис. 6. Слева новое судоку, полученное из опубликованного С. Скиена путём перестановки групп колонок по случайному закону. Справа, судоку опубликованное С. Скиена.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
#rnd = list('123456789')
#shuffle(rnd)
#for i in range(0, 8, 2):
# skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
# перестановка групп колонок и колонок в своих группах
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
for n in range(81):
play(n)
mainloop() # Главный цикл программы
Лист. 9. Функция init переписана так, что теперь осуществляется перестановка групп колонок и колонок в своих группах по случайным законам.
Рис. 7. Слева новое судоку, полученное путём перестановки групп колонок и колонок в своих группах по случайным законам. Справа, судоку опубликованное С. Скиена.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
## rnd = list('123456789')
## shuffle(rnd)
## for i in range(0, 8, 2):
## skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
## shuffle(rnd_g)
## back_skiena = skiena.copy()
## back_playground = playground.copy()
## for g in range(3): # цикл по группам колонок
## shuffle(rnd_c)
## for c in range(3): # цикл по столбцам в группе столбцов
## for r in range(9): # цикл по строкам в таблице
## skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
## playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*3+r+c*9] = back_playground[rnd_g[g]*3+rnd_c[r]+c*9]
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
for n in range(81):
play(n)
mainloop() # Главный цикл программы
Лист. 10. Функция init переписана так, что теперь осуществляется перестановка групп строк и строк в своих группах по случайным законам.
Рис. 8. Слева новое судоку, полученное путём перестановки групп строк и строк в своих группах по случайным законам. Справа, судоку опубликованное С. Скиена.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
for n in range(81):
play(n)
mainloop() # Главный цикл программы
Лист. 11. Функция init теперь осуществляет замену цифр на другие, замену групп колонок и колонок в своих группах, замену групп строк и строк в своих группах по случайным законам.
Рис. 9. Слева новое судоку, полученное путём замены цифр на другие, замены групп колонок и колонок в своих группах, замены групп строк и строк в своих группах по случайным законам. Справа, судоку опубликованное С. Скиена.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init():
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
return skiena, playground
skiena, playground = init()
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
if playground[n]:
btn[n].config(text=skiena[n]) # Начальное состояние (Подсказки)
n += 1
mainloop() # Главный цикл программы
Лист. 12. Программа, генерирующая игровое поле с подсказками для игры судоку.
Рис. 10. Состояние игрового поля в начале игры сгенерированное программой листинг 12, слева, и сгенерированное программой листинг 3, справа.
На рис. 10 мы видим 2 игровых поля в начальном состоянии игры. Левое поле сгенерировано из правого поля путём замен и перестановок программой листинг 12. Все замены и перестановки в программе листинг 12 в функции init осуществляются с учётом правил игры судоку. Каждая новая игра, сгенерированная программой листинг 12 имеет решение.
Упражнение. Зная алгоритм программы листинг 12, не без труда, можно вычислить ход преобразований правого игрового игрового поля (исходник) изображённого на рисунке 10 в левый вариант игрового поля (вариант) с этого же рисунка.
Пустая группа клеток на исходнике занимала левый верхний угол, а в варианте эта же группа занимает центр игрового поля. Значит группа колонок № 0 переместилась в № 1, а группа строк № 0 переместилась в № 1.
Группа клеток с одной цифрой на исходнике занимала центр игрового поля, а в варианте эта же группа занимает левый верхний угол. Значит группа колонок № 1 переместилась в № 0, а группа строк № 1 переместилась в № 0.
Выше изложенного достаточно чтобы разобраться со всеми трансформациями групп клеток:
- группа строк № 0 переместилась в группу строк № 1,
- группа строк № 1 переместилась в группу строк № 0,
- группа строк № 3 осталась на своём месте,
- группа колонок № 0 переместилась в группу колонок № 1,
- группа колонок № 1 переместилась в группу колонок № 0,
- группа колонок № 3 осталась на своём месте.
Группа клеток с одной цифрой единственная на поле и на исходнике содержит цифру 4, на варианте цифра 4 превратилась в цифру 1. Так как, в программе листинг 12 цифры меняются парами, мы делаем вывод, что там где в исходнике была цифра 1 на варианте будет цифра 4.
На исходнике цифра 4 встречается всего 2 раза. Первый случай мы разобрали, во втором случае цифра 4 находится в группе клеток с цифрой 6. На варианте цифра 1 находится в в группе клеток с цифрой 7. Значит цифра 6 поменялась на 7, а цифра 7 на 6.
Таким образом, можно вычислить ход всех преобразований, включая перестановку строк в своих группах и перестановку колонок в своих группах.
************
Программа листинг 12 генерирует самые сложные из известных вариантов судоку, поэтому нам необходимо добавить в программу возможность выбора уровня игры.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init(level):
global skiena, playground
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
init(0)
mainloop() # Главный цикл программы
Лист. 13. Генератор вариантов судоку с кнопками выбора уровня игры.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
btn[n].config(text=skiena[n])
def init(level):
global skiena, playground
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
init(0)
mainloop() # Главный цикл программы
Лист. 14. Генератор вариантов судоку с возможностью выбора уровня игры.
Рис. 11. Игровые поля сгенерированные программой листинг 14, слева - уровень 1, по центру - уровень 2, справа - уровень 3.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
def init(level):
global skiena, playground
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
f = Frame() # Нижний фрейм
f.pack(expand=YES, fill=BOTH)
scl = Scale(from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
init(0)
mainloop() # Главный цикл программы
Лист. 15. В программу добавлена цифровая шкала и, в функции play, реализована возможность вывода цифр на кнопки игрового поля.
Рис. 12. Игровое поле с возможностью выбора цифры для очередного хода.
Программа листинг 15 пригодна для игры в судоку, но ошибки, сделанные игроком в процессе игры, в ней не учитываются. Пора добавить в программу счётчик ошибок.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
tk = Tk()
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
f = Frame() # Нижний фрейм
f.pack(expand=YES, fill=BOTH)
scl = Scale(from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
init(0)
mainloop() # Главный цикл программы
Лист. 16. Программа судоку со счётчиком ошибок.
Рис. 13. Программа судоку со счётчиком ошибок.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
f = Frame() # Нижний фрейм
f.pack(expand=YES, fill=BOTH)
scl = Scale(from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
init(0)
mainloop() # Главный цикл программы
Лист. 17. Программа судоку с окном справки.
Рис. 14. Программа судоку и окно справки.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
def colores(n): # Установить цвет кнопок
for i in range(81):
btn[i].config(bg='#ddd')
rgb = btn[i].cget('bg')
rgb = '#' + chr(ord(rgb[1]) + 1) + chr(ord(rgb[2]) + 1) + chr(ord(rgb[3]) - 1)
btn[i].config(activebackground = rgb)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
n = 0
for i in range(3):
f = Frame() # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
f = Frame() # Нижний фрейм
f.pack(expand=YES, fill=BOTH)
scl = Scale(from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
init(0)
colores(0)
mainloop() # Главный цикл программы
Лист. 18. В программу добавлена функция colores.
Рис. 14. Программа судоку с заданными цветами кнопок.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
rgb = btn[i].cget('bg')
rgb = '#' + chr(ord(rgb[1]) + 1) + chr(ord(rgb[2]) + 1) + chr(ord(rgb[3]) - 1)
btn[i].config(activebackground = rgb)
def cheri(): # Обслуживание кнопок в правом меню
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
rmenu = ('Считать\nцифры', 'Удалять\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
colores(0)
mainloop() # Главный цикл программы
Лист. 19. В программу добавлены кнопки правого меню.
Рис. 15. Добавлены кнопки правого меню.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
rgb = btn[i].cget('bg')
rgb = '#' + chr(ord(rgb[1]) + 1) + chr(ord(rgb[2]) + 1) + chr(ord(rgb[3]) - 1)
btn[i].config(activebackground = rgb)
def cheri(): # Обслуживание кнопок в правом меню
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Если вы испытываете трудность в выборе хода,'
'воспользуйтесь кнопками справа',
font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
rmenu = ('Считать\nцифры', 'Удалять\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
colores(0)
mainloop() # Главный цикл программы
Лист. 20. В программу добавлена строка помощи (Label).
Рис. 16. Добавленf строка помощи.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
rgb = btn[i].cget('bg')
rgb = '#' + chr(ord(rgb[1]) + 1) + chr(ord(rgb[2]) + 1) + chr(ord(rgb[3]) - 1)
btn[i].config(activebackground = rgb)
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число')
scl.pack()
rmenu = ('Считать\nцифры', 'Удалять\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
colores(0)
countnumb()
mainloop() # Главный цикл программы
Лист. 21. В программу добавлена функция countnumb() для подсчёта цифр на поле.
Рис. 17. Цифры на поле пересчитаны.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if chevar[1].get() and playground[i] and skiena[i] == n:
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 22. В программу добавлена функция для выделения выбранных цифр на игровом поле.
Рис. 18. На игровом поле выделены цифры "2". Цифра "2" выбранна на цифровой шкале.
from tkinter import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if chevar[1].get() and playground[i] and skiena[i] == n:
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
k = 0
for i in range(81):
if playground[i] and skiena[i] == n:
k += 1
for i in range(81):
if k == 9 and chevar[2].get():
btn[i].config(state=DISABLED)
else:
btn[i].config(state=NORMAL)
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 23. В программу добавлена возможность заблокировать игровое поле.
Рис. 19. На цифровой шкале выбрана цифра 1. Игровое поле заблокировано.
from tkinter import * # Графическая библиотека
from tkinter.messagebox import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if chevar[3].get():
whatis(n)
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if chevar[1].get() and playground[i] and skiena[i] == n:
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
if chevar[3].get():
scl.config(state=DISABLED)
else:
scl.config(state=NORMAL)
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def whatis(kn):
numb = set(range(1, 10))
def numb_remove(n):
if playground[n]: # если кнопка открыта
numb.discard(skiena[n])
knrow = (kn // 9) # номер строки
kncol = kn % 9 # номер первой кнопки в колонке = номер колонки
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for i in range(3):
for j in range(0,19,9):
numb_remove(knblock+i+j)# цикл по блоку
for i in range(kncol, 81, 9):
numb_remove(i) # цикл по колонке
for i in range(knrow*9, (knrow+1)*9):
numb_remove(i) # цикл по строке
showinfo(title="Совет для ячейки № "+str(kn),
message="Попробуйте одну из цифр\n" + str(numb))
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
k = 0
for i in range(81):
if playground[i] and skiena[i] == n:
k += 1
for i in range(81):
if k == 9 and chevar[2].get():
btn[i].config(state=DISABLED)
else:
btn[i].config(state=NORMAL)
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры', 'Что\nвыбрать')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 24. В программу добавле.
Рис. 19. На .
from tkinter import * # Графическая библиотека
from tkinter.messagebox import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if chevar[3].get():
whatis(n)
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if (chevar[1].get() and playground[i] and skiena[i] == n
or chevar[6].get() and playground[i]):
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
if chevar[3].get():
scl.config(state=DISABLED)
else:
scl.config(state=NORMAL)
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def whatis(kn):
numb = set(range(1, 10))
def numb_remove(n):
if playground[n]: # если кнопка открыта
numb.discard(skiena[n])
knrow = (kn // 9) # номер строки
kncol = kn % 9 # номер первой кнопки в колонке = номер колонки
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for i in range(3):
for j in range(0,19,9):
numb_remove(knblock+i+j)# цикл по блоку
for i in range(kncol, 81, 9):
numb_remove(i) # цикл по колонке
for i in range(knrow*9, (knrow+1)*9):
numb_remove(i) # цикл по строке
showinfo(title="Совет для ячейки № "+str(kn),
message="Попробуйте одну из цифр\n" + str(numb))
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
k = 0
for i in range(81):
if playground[i] and skiena[i] == n:
k += 1
for i in range(81):
if k == 9 and chevar[2].get():
btn[i].config(state=DISABLED)
else:
btn[i].config(state=NORMAL)
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры', 'Что\nвыбрать',
'Выделять\nлинии', 'Выделять\nблоки', 'Выделять\nвсе\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 25. В программу добавле.
Рис. 20. На .
from tkinter import * # Графическая библиотека
from tkinter.messagebox import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if chevar[3].get():
whatis(n)
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if (chevar[1].get() and playground[i] and skiena[i] == n
or chevar[6].get() and playground[i]):
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
for i in range(81):
knrow = (i // 9) # номер строки
kncol = i % 9 # номер первой кнопки в колонке = номер колонки
if chevar[5].get() and playground[i] and skiena[i] == n:
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for l in range(3):
for j in range(0,19,9):
btn[knblock+l+j].config(bg='#aaa') # цикл по блоку
if playground[knblock+l+j]:
btn[knblock+l+j].config(activebackground = '#aaa')
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
if chevar[3].get():
scl.config(state=DISABLED)
else:
scl.config(state=NORMAL)
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def whatis(kn):
numb = set(range(1, 10))
def numb_remove(n):
if playground[n]: # если кнопка открыта
numb.discard(skiena[n])
knrow = (kn // 9) # номер строки
kncol = kn % 9 # номер первой кнопки в колонке = номер колонки
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for i in range(3):
for j in range(0,19,9):
numb_remove(knblock+i+j)# цикл по блоку
for i in range(kncol, 81, 9):
numb_remove(i) # цикл по колонке
for i in range(knrow*9, (knrow+1)*9):
numb_remove(i) # цикл по строке
showinfo(title="Совет для ячейки № "+str(kn),
message="Попробуйте одну из цифр\n" + str(numb))
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
k = 0
for i in range(81):
if playground[i] and skiena[i] == n:
k += 1
for i in range(81):
if k == 9 and chevar[2].get():
btn[i].config(state=DISABLED)
else:
btn[i].config(state=NORMAL)
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры', 'Что\nвыбрать',
'Выделять\nлинии', 'Выделять\nблоки', 'Выделять\nвсе\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 26. В программу добавле.
Рис. 21. На .
from tkinter import * # Графическая библиотека
from tkinter.messagebox import * # Графическая библиотека
from random import shuffle # Перемешать список suffle(A)
btn = [] # Список кнопок на игровом поле
m_level = [] # Список кнопок выбора уровня игры
sclold = 1 # Начальная позиция ползунка
def play(n): # функция обработчик нажатия на кнопку
global miss
if playground[n]:
return
if chevar[3].get():
whatis(n)
return
if int(scl.get()) == skiena[n]:
btn[n].config(text=skiena[n])
playground[n] = 1
if not playground.count(0):
tk.title('Вы победили')
else: # игрок допустил ошибку
miss += 1
tk.title('Вы ошиблись ' + str(miss) + ' раз')
countnumb()
sclblock(0)
def countnumb():
report = 'Если вы испытываете трудность в выборе хода, воспользуйтесь кнопками справа'
if chevar[0].get() == 1:
report = 'Цифры на поле пересчитаны: '
for i in range(1, 10):
n = 0
for j in range(81):
if playground[j] and skiena[j] == i:
n += 1
report += str(i) + ' :: ' + str(n) + ' '
lbl.config(text=report)
def init(level):
global skiena, playground, miss
miss = 0 # Счётчик ошибок
tk.title('СУДОКУ')
skiena = '673894512912735486845612973798261354526473891134589267469128735287356149351947628'
playground = '000000011000011000000100010100000100000100100100000000000110000010000010010000100'
playground = [bool(int(i)) for i in list(playground)] # Клетки открыты если True
# Выбор уровня игры
rnd = [i for i in range(81) if not playground[i]]
shuffle(rnd)
for i in range(level * 5):
playground[rnd[i]] = 1
# замена одних цифр другими по случайному закону
rnd = list('123456789')
shuffle(rnd)
for i in range(0, 8, 2):
skiena = skiena.replace(rnd[i], 'x').replace(rnd[i+1], rnd[i]).replace('x', rnd[i+1])
skiena = [(int(i)) for i in list(skiena)]
rnd_g = [0, 1, 2]
rnd_c = [0, 1, 2]
# перестановка групп колонок и колонок в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам колонок
shuffle(rnd_c)
for c in range(3): # цикл по столбцам в группе столбцов
for r in range(9): # цикл по строкам в таблице
skiena[g*3+c+r*9] = back_skiena[rnd_g[g]*3+rnd_c[c]+r*9]
playground[g*3+c+r*9] = back_playground[rnd_g[g]*3+rnd_c[c]+r*9]
# перестановка групп строк и строк в своих группах
shuffle(rnd_g)
back_skiena = skiena.copy()
back_playground = playground.copy()
for g in range(3): # цикл по группам строк
shuffle(rnd_c)
for r in range(3): # цикл по строкам в группе строк
for c in range(9): # цикл по колонкам в таблице
skiena[g*27+r*9+c] = back_skiena[rnd_g[g]*27+rnd_c[r]*9+c]
playground[g*27+r*9+c] = back_playground[rnd_g[g]*27+rnd_c[r]*9+c]
for n in range(81): # вывод сгенерированного вырианта на игровое поле
btn[n].config(text='')
if playground[n]:
btn[n].config(text=skiena[n]) # начальное состояние (Подсказки)
countnumb()
sclblock(0)
colores(int(scl.get()))
def colores(n): # Установить цвет кнопок на игровом поле
for i in range(81):
btn[i].config(bg='#ddd')
if (chevar[1].get() and playground[i] and skiena[i] == n
or chevar[6].get() and playground[i]):
btn[i].config(bg='#aaa')
if not playground[i]:
btn[i].config(activebackground = '#eec')
else:
btn[i].config(activebackground = btn[i].cget('bg'))
for i in range(81):
knrow = (i // 9) # номер строки
kncol = i % 9 # номер первой кнопки в колонке = номер колонки
if chevar[5].get() and playground[i] and skiena[i] == n:
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for l in range(3): # цикл по блоку
for j in range(0,19,9):
btn[knblock+l+j].config(bg='#aaa')
if playground[knblock+l+j]:
btn[knblock+l+j].config(activebackground = '#aaa')
if chevar[4].get() and playground[i] and skiena[i] == n:
for j in range(kncol, 81, 9): # цикл по колонке
btn[j].config(bg='#aaa')
if playground[j]:
btn[j].config(activebackground = '#aaa')
for j in range(knrow*9, (knrow+1)*9): # цикл по строке
btn[j].config(bg='#aaa')
if playground[j]:
btn[j].config(activebackground = '#aaa')
def cheri(): # Обслуживание кнопок в правом меню
countnumb()
sclblock(0)
colores(int(scl.get()))
if chevar[3].get():
scl.config(state=DISABLED)
else:
scl.config(state=NORMAL)
for i in range(len(chevar)):
if chevar[i].get():
chebtn[i].config(relief=RIDGE)
else:
chebtn[i].config(relief=GROOVE)
pass
def whatis(kn):
numb = set(range(1, 10))
def numb_remove(n):
if playground[n]: # если кнопка открыта
numb.discard(skiena[n])
knrow = (kn // 9) # номер строки
kncol = kn % 9 # номер первой кнопки в колонке = номер колонки
knblock = (kncol//3)*3 + (knrow//3)*27 # номер первой кнопки в блоке
for i in range(3):
for j in range(0,19,9):
numb_remove(knblock+i+j)# цикл по блоку
for i in range(kncol, 81, 9):
numb_remove(i) # цикл по колонке
for i in range(knrow*9, (knrow+1)*9):
numb_remove(i) # цикл по строке
showinfo(title="Совет для ячейки № "+str(kn),
message="Попробуйте одну из цифр\n" + str(numb))
def sclblock(self): # Обслуживани цифровой шкалы
n = int(scl.get())
k = 0
for i in range(81):
if playground[i] and skiena[i] == n:
k += 1
for i in range(81):
if k == 9 and chevar[2].get():
btn[i].config(state=DISABLED)
else:
btn[i].config(state=NORMAL)
colores(n)
def help_win():
tplvl = Toplevel(tk)
tplvl.title("Справка по судоку")
x_position = 300
y_position = 200
tplvl.geometry(f"600x800+{x_position}+{y_position}")
Label(tplvl, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(10, 20), sticky="e")
msg = Message(tplvl, width=500, text="Логическая игра судоку\n"
"Кнопки L1, L2, L3 позволяют выбирать различные уровни игры\n"
"L1 содержит 17 цифр - подсказок\n"
"L2 содержит 22 цифры - подсказки\n"
"L3 содержит 27 цифр - подсказок\n"
"Ход игры.\nПод игровым полем на линейке выберите желаемую цифру. "
"Щёлкните мышью по клетке на игровом поле, чтобы вывести в эту клетку вашу цифру. "
"Если вы ошиблись с выбором цифры, в строке заголовка она игры появится счётчик ошибок.\n"
"Вы можете продолжать игру, стремясь ошибаться как можно меньше.\n"
"\nSudoku License\n"
"This is my version of the game, known as Sudoku.\n"
"Author: Diorditsa A. Created on August 2024.\n"
"sudocu.py is distributed in the hope that it will be useful, but "
"WITHOUT WARRANTY OF ANY KIND; not even an implied warranty "
"MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee.\n"
"See the GNU General Public License for more information. "
"You can get a copy of the GNU General Public License by link http://www.gnu.org/licenses/")
msg.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
Button(tplvl, text="OK", command=tplvl.destroy, width=10).grid(row=1, column=1, sticky="e")
tk = Tk()
lbl = Label(text='Hello!', font='Ubuntu 12', pady=8) # Верхняя строка (topcontent)
lbl.pack(expand=YES, fill=BOTH)
f = Frame() # Левый фрейм (leftmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
h1 = Button(f, text='He', width=3, height=1, font='Ubuntu 16') # инструкция
h1.config(command=help_win)
h1.pack(expand=YES, fill=BOTH)
for i in range(3): # Создание кнопок выбора уровня игры
m_level += [Button(f, text='L'+str(i+1))]
m_level[-1].pack(expand=YES, fill=BOTH)
m_level[-1].config(width=3, height=1, font='Ubuntu 16')
m_level[-1].config(command=lambda n=i: init(n))
fc = Frame() # Центральный фрейм (content)
fc.pack(expand=YES, fill=BOTH, side=LEFT)
n = 0
for i in range(3):
f = Frame(fc) # Три строки для блоков 3х3
f.pack(expand=YES, fill=BOTH) # Вывод строк-фреймов, следующий под преыдущим
frm = [] # Список вложенных в строки блоков-фреймов 3х3
for i in range(3): # В каждой из 3-х строк 3 блока
frm += [Frame(f, borderwidth=3, relief="raised")]
frm[i].pack(expand=YES, fill=BOTH, side=LEFT)
# В строке уже размещены 3 блока-фрейма, они именованы как frm[1], frm[2], frm[3]
for i in range(3):
for i in frm: # Цикл по блокам в строке
f = Frame(i) # В каждом блоке создаём строчку-фрейм для 3-х кнопок
f.pack(expand=YES, fill=BOTH)
for j in range(3):
btn += [Button(f)]
btn[n].pack(expand=YES, fill=BOTH, side=LEFT)
btn[n].config(width=3, height=2, font='Ubuntu 24')
btn[n].config(command=lambda n=n: play(n))
n += 1
scl = Scale(fc, from_=1, to=9, tickinterval=1, resolution=1, showvalue=NO,
length=600, orient='horizontal', label='Выберите число',
command = sclblock)
scl.pack()
rmenu = ('Считать\nцифры', 'Выделять\nцифры', 'Блокировать\nцифры', 'Что\nвыбрать',
'Выделять\nлинии', 'Выделять\nблоки', 'Выделять\nвсе\nцифры')
chevar = []
chebtn = []
f = Frame() # Правый фрейм (rightmenu)
f.pack(expand=YES, fill=BOTH, side=LEFT)
for i in range(len(rmenu)):
chevar += [IntVar()]
chebtn += [Checkbutton(f, text=rmenu[i], command=cheri, variable=chevar[i],
borderwidth=6, anchor=W, width=12, justify=CENTER,
relief=GROOVE)]
chebtn[i].pack(fill=BOTH)
init(0)
mainloop() # Главный цикл программы
Лист. 27. В программу добавле.
Рис. 22. На .
Литература: Стивен С. Скиена. Алгоритмы. Руководство по разработке. 2-е издание. Санкт-Петербург "БХВ-Петербург" 2021.
Интернет ресурс Python tkinter Checkbutton Widget.