Введение
В этом проекте мы создадим игру Судоку с использованием Python и библиотеки Pygame. Игра сгенерирует сетку Судоку заданного уровня сложности и позволит игрокам решать головоломку, заполняя пустые клетки цифрами. Игра будет предоставлять функции, такие как выбор уровня сложности, подсветка выбранных клеток и проверка, заполнена ли сетка.
👀 Предпросмотр

🎯 Задачи
В этом проекте вы научитесь:
- Как импортировать необходимые библиотеки
- Как инициализировать PyGame
- Как определить цвета
- Как установить размеры и заголовок игрового окна
- Как создать игровое окно
- Как загрузить шрифты
- Как сгенерировать сетку Судоку
- Как решить сетку Судоку с использованием алгоритма обратного хода
- Как удалить цифры из сетки в зависимости от сложности
- Как нарисовать сетку Судоку на игровом окне
- Как проверить, заполнена ли сетка полностью
- Как получить координаты клетки под позицией мыши
- Как выбрать уровень сложности
- Как реализовать главный игровой цикл
🏆 Достижения
После завершения этого проекта вы сможете:
- Использовать библиотеку Pygame для разработки игр на Python
- Генерировать сетку Судоку заданного уровня сложности
- Решать сетку Судоку с использованием алгоритма обратного хода
- Обрабатывать события мыши и клавиатуры в Pygame
- Рисовать фигуры и текст на игровом окне
- Реализовать главный игровой цикл в Pygame
Создайте файлы проекта
Для начала создайте файл с именем sudoku_game.py и откройте его в предпочитаемом текстовом редакторе или интегрированной среде разработки (IDE).
cd ~/project
touch sudoku_game.py
Импортируйте необходимые библиотеки
Импортируйте необходимые библиотеки в начале файла. Для этой игры нам нужны библиотеки pygame и random.
import pygame
import random
Установите библиотеку pygame с помощью команды pip.
sudo pip install pygame
Инициализируйте PyGame
Инициализируйте библиотеку PyGame для настройки игрового окна.
pygame.init()
Определите цвета
Определите цвета, которые будут использоваться в игре. Мы будем использовать формат RGB для цветов.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
BLUE = (0, 0, 255)
LIGHT_BLUE = (100, 100, 255)
Установите размеры и заголовок игрового окна
Установите размеры игрового окна и задайте заголовок для игры.
WINDOW_SIZE = (550, 550)
CELL_SIZE = WINDOW_SIZE[0] // 9
pygame.display.set_caption("Sudoku Game")
Создайте игровое окно
Создайте игровое окно с использованием указанных размеров.
screen = pygame.display.set_mode(WINDOW_SIZE)
Загрузите шрифты
Нам понадобится загрузить шрифты, чтобы отображать цифры на игровом экране. Загрузите два шрифта, один для больших цифр и другой для маленьких цифр.
font_large = pygame.font.SysFont("calibri", 50)
font_small = pygame.font.SysFont("calibri", 30)
Сгенерируйте сетку Судоку
Создайте функцию generate_sudoku(difficulty), которая генерирует новую сетку Судоку заданного уровня сложности. Функция должна возвращать сгенерированную сетку.
def generate_sudoku(difficulty):
## Function code goes here
pass
Заполните диагональные подсетки
Внутри функции generate_sudoku заполните диагональные подсетки сетки случайными числами. Это гарантирует, что в каждой подсетке содержатся числа от 1 до 9 без повторений.
## Fill diagonal subgrids
for i in range(0, 9, 3):
nums = random.sample(range(1, 10), 3)
for j in range(3):
grid[i + j][i + j] = nums[j]
Решите сетку Судоку
Создайте функцию solve_sudoku(grid), которая решает сетку Судоку с использованием алгоритма обратного хода. Функция должна возвращать True, если сетка разрешима, и False в противном случае.
def solve_sudoku(grid):
## Function code goes here
pass
Найдите пустую ячейку
Внутри функции solve_sudoku создайте вспомогательную функцию find_empty_cell(grid), которая возвращает координаты следующей пустой ячейки в сетке. Если пустых ячеек нет, верните None.
def find_empty_cell(grid):
for row in range(9):
for col in range(9):
if grid[row][col] == 0:
return (row, col)
return None
Проверьте допустимый ход
Внутри функции solve_sudoku создайте вспомогательную функцию is_valid_move(grid, row, col, num), которая проверяет, является ли размещение числа в ячейке допустимым ходом. Функция должна возвращать True, если ход допустим, и False в противном случае.
def is_valid_move(grid, row, col, num):
## Function code goes here
pass
Решите сетку Судоку (продолжение)
Внутри функции solve_sudoku используйте вспомогательные функции find_empty_cell и is_valid_move для реализации алгоритма обратного хода. Если решение найдено, верните True. Если текущее число приводит к недопустимому решению, открутите назад, установив текущую ячейку равной 0.
## Try filling the empty cell with numbers from 1 to 9
for num in range(1, 10):
if is_valid_move(grid, row, col, num):
grid[row][col] = num
if solve_sudoku(grid):
return True
## If the current number leads to an invalid solution, backtrack
grid[row][col] = 0
return False
Удалите числа в зависимости от сложности
Внутри функции generate_sudoku удалите числа из сетки в зависимости от указанного уровня сложности. Уровни сложности: 1 (легко), 2 (средне), 3 (сложно). Количество чисел для удаления вычисляется как num_to_remove = 45 + 10 * difficulty.
## Remove numbers based on difficulty level
num_to_remove = 45 + 10 * difficulty
for _ in range(num_to_remove):
row = random.randint(0, 8)
col = random.randint(0, 8)
grid[row][col] = 0
return grid
Нарисуйте сетку
Создайте функцию draw_grid(grid, selected_cell), которая рисует сетку Судоку на игровом окне. Эта функция должна отвечать за рисование ячеек, цифр и выделение выбранной ячейки.
def draw_grid(grid, selected_cell):
## Function code goes here
pass
Заполните клетки и нарисуйте цифры
Внутри функции draw_grid пройдитесь по сетке и нарисуйте ячейки и цифры с использованием функций Pygame pygame.draw.rect и screen.blit.
## Draw the cells
for row in range(9):
for col in range(9):
cell_rect = pygame.Rect(
col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE, CELL_SIZE
)
pygame.draw.rect(screen, GRAY, cell_rect)
## Draw the numbers
if grid[row][col]!= 0:
number = font_small.render(str(grid[row][col]), True, BLACK)
text_rect = number.get_rect(
center=(
col * CELL_SIZE + CELL_SIZE // 2,
row * CELL_SIZE + CELL_SIZE // 2,
)
)
screen.blit(number, text_rect)
Выделите выбранную клетку
Внутри функции draw_grid выделите выбранную ячейку, если она не равна None, с использованием функции pygame.draw.rect.
## Highlight the selected cell
if (row, col) == selected_cell:
pygame.draw.rect(screen, LIGHT_BLUE, cell_rect, 3)
Нарисуйте линии сетки
Внутри функции draw_grid нарисуйте линии для создания сетки с использованием функции pygame.draw.line.
## Draw the lines
for i in range(10):
if i % 3 == 0:
thickness = 4
else:
thickness = 1
pygame.draw.line(
screen,
BLACK,
(0, i * CELL_SIZE),
(WINDOW_SIZE[0], i * CELL_SIZE),
thickness,
)
pygame.draw.line(
screen,
BLACK,
(i * CELL_SIZE, 0),
(i * CELL_SIZE, WINDOW_SIZE[1]),
thickness,
)
Обновите отображение
Внутри функции draw_grid обновите экран с использованием функции pygame.display.update.
pygame.display.update()
Проверьте, заполнена ли сетка
Создайте функцию is_grid_full(grid), которая проверяет, заполнена ли сетка Судоку полностью. Это можно сделать, пройдясь по сетке и проверив, содержит ли какая-либо ячейка 0.
def is_grid_full(grid):
## Function code goes here
pass
Получите клетку под мышью
Создайте функцию get_cell_under_mouse(pos), которая возвращает координаты ячейки под позицией мыши. Это можно вычислить, разделив позицию мыши на размер ячейки.
def get_cell_under_mouse(pos):
## Function code goes here
pass
Выберите сложность
Создайте функцию select_difficulty(), которая позволяет игроку выбрать уровень сложности перед началом игры. Эта функция должна отображать варианты сложности и возвращать выбранный уровень сложности.
def select_difficulty():
## Function code goes here
pass
Реализуйте выбор сложности
Внутри функции select_difficulty реализуйте логику выбора сложности с использованием функций Pygame pygame.mouse.get_pos и pygame.event.get.
## Display difficulty selection text
title_text = font_large.render("Select Difficulty", True, BLACK)
screen.blit(title_text, (110, 200))
## Display difficulty options
option_y = 300
for difficulty, label in difficulties.items():
option_text = font_small.render(f"{difficulty}. {label}", True, BLACK)
text_rect = option_text.get_rect(center=(WINDOW_SIZE[0] // 2, option_y))
screen.blit(option_text, text_rect)
option_y += 70
pygame.display.update()
## Wait for difficulty selection
difficulty_selected = False
difficulty = 1
while not difficulty_selected:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: ## Left mouse button
pos = pygame.mouse.get_pos()
if 180 <= pos[0] <= 380:
if 300 <= pos[1] <= 350:
difficulty = 1
difficulty_selected = True
elif 370 <= pos[1] <= 420:
difficulty = 2
difficulty_selected = True
elif 440 <= pos[1] <= 490:
difficulty = 3
difficulty_selected = True
return difficulty
Основной игровой цикл
Создайте основной игровой цикл, определив функцию main().
def main():
## Function code goes here
pass
Выберите сложность и сгенерируйте сетку
Внутри функции main выберите уровень сложности, вызвав select_difficulty(), и верните, если сложность равна None. Затем сгенерируйте сетку Судоку с использованием выбранного уровня сложности, вызвав generate_sudoku(difficulty).
## Select the difficulty level
difficulty = select_difficulty()
if difficulty is None:
return
## Generate a new Sudoku grid
grid = generate_sudoku(difficulty)
Переменные игрового цикла
Внутри функции main создайте переменные игрового цикла selected_cell и running. Установите selected_cell в None и running в True.
selected_cell = None
running = True
Включить повтор нажатия клавиш
Внутри функции main включите повтор нажатия клавиш с использованием функции pygame.key.set_repeat. Мы устанавливаем задержку и интервал в 100 миллисекунд, чтобы сделать проще для игроков заполнять клетки.
## Enable key repeat
pygame.key.set_repeat(100, 100)
Обработка событий
Внутри игрового цикла обрабатывайте события с использованием функции pygame.event.get. Проверяйте на события выхода, нажатия кнопок мыши и нажатия клавиш.
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
## Handle mouse button events
pass
elif event.type == pygame.KEYDOWN:
## Handle key events
pass
Обработка событий нажатия кнопок мыши
Внутри обработки событий нажатия кнопок мыши проверьте, нажата ли левая кнопка мыши или правая кнопка мыши.
if event.button == 1: ## Left mouse button
## Handle left mouse button click
pass
elif event.button == 3: ## Right mouse button
## Handle right mouse button click
pass
Обработка нажатия левой кнопки мыши
Внутри обработки нажатия левой кнопки мыши получите координаты клетки под позицией мыши, вызвав get_cell_under_mouse(pos).
## Get the cell under the mouse position
pos = pygame.mouse.get_pos()
row, col = get_cell_under_mouse(pos)
Обработка нажатия левой кнопки мыши (продолжение)
Внутри обработки нажатия левой кнопки мыши выберите клетку, если она пуста, проверив, равно ли grid[row][col] 0.
## Select the cell if it's empty
if grid[row][col] == 0:
selected_cell = (row, col)
Обработка нажатия правой кнопки мыши
Внутри обработки нажатия правой кнопки мыши очистите выбранную клетку, если она не равна None и она пуста, проверив, равно ли grid[selected_cell[0]][selected_cell[1]] 0.
if selected_cell:
## Clear the selected cell if it's empty
if grid[selected_cell[0]][selected_cell[1]] == 0:
grid[selected_cell[0]][selected_cell[1]] = 0
Обработка событий клавиатуры
Внутри обработки событий клавиатуры проверьте, какая цифровая клавиша нажата, и установите значение выбранной клетки соответственно.
if selected_cell:
## Get the key pressed
if event.key == pygame.K_1:
grid[selected_cell[0]][selected_cell[1]] = 1
elif event.key == pygame.K_2:
grid[selected_cell[0]][selected_cell[1]] = 2
elif event.key == pygame.K_3:
grid[selected_cell[0]][selected_cell[1]] = 3
elif event.key == pygame.K_4:
grid[selected_cell[0]][selected_cell[1]] = 4
elif event.key == pygame.K_5:
grid[selected_cell[0]][selected_cell[1]] = 5
elif event.key == pygame.K_6:
grid[selected_cell[0]][selected_cell[1]] = 6
elif event.key == pygame.K_7:
grid[selected_cell[0]][selected_cell[1]] = 7
elif event.key == pygame.K_8:
grid[selected_cell[0]][selected_cell[1]] = 8
elif event.key == pygame.K_9:
grid[selected_cell[0]][selected_cell[1]] = 9
Нарисовать сетку и проверить завершение
Внутри игрового цикла отрисуйте сетку, вызвав draw_grid(grid, selected_cell). Затем проверьте, завершена ли сетка, вызвав is_grid_full(grid).
## Draw the grid
draw_grid(grid, selected_cell)
## Check if the grid is complete
if is_grid_full(grid):
print("Congratulations! You solved the Sudoku puzzle.")
Обновить отображение и выйти
После игрового цикла обновите отображение с использованием функции pygame.display.update и выйдите из игры с использованием pygame.quit().
## Update the display
pygame.display.update()
## Quit the game
pygame.quit()
Запустить игру
Наконец, добавьте условие для проверки, является ли текущий файл точкой входа в программу. Если да, запустите игру, вызвав функцию main().
if __name__ == "__main__":
main()
Запустите игру с использованием команды python.
python sudoku_game.py

Резюме
Поздравляем! Вы успешно создали игру Судоку с использованием Python и библиотеки Pygame. В игре игроки могут выбрать уровень сложности, заполнять пустые клетки цифрами и проверять, завершена ли сетка. Приятной игры и решения пазлов Судоку!



