Introdução
Neste projeto, criaremos um jogo de Sudoku usando Python e a biblioteca Pygame. O jogo gerará uma grade de Sudoku com o nível de dificuldade especificado e permitirá que os jogadores resolvam o quebra-cabeça preenchendo as células vazias com números. O jogo fornecerá recursos como seleção de dificuldade, destaque de células selecionadas e verificação se a grade está completa.
👀 Pré-visualização

🎯 Tarefas
Neste projeto, você aprenderá:
- Como importar as bibliotecas necessárias
- Como inicializar o PyGame
- Como definir cores
- Como definir as dimensões e o título da janela do jogo
- Como criar a janela do jogo
- Como carregar fontes
- Como gerar uma grade de Sudoku
- Como resolver a grade de Sudoku usando o algoritmo de backtracking
- Como remover números da grade com base na dificuldade
- Como desenhar a grade de Sudoku na janela do jogo
- Como verificar se a grade está totalmente preenchida
- Como obter as coordenadas da célula sob a posição do mouse
- Como selecionar o nível de dificuldade
- Como implementar o loop principal do jogo
🏆 Conquistas
Após concluir este projeto, você será capaz de:
- Usar a biblioteca Pygame para desenvolvimento de jogos em Python
- Gerar uma grade de Sudoku com um nível de dificuldade especificado
- Resolver uma grade de Sudoku usando o algoritmo de backtracking
- Lidar com eventos de mouse e teclado no Pygame
- Desenhar formas e texto na janela do jogo
- Implementar o loop principal do jogo no Pygame
Criar os Arquivos do Projeto
Para começar, crie um arquivo chamado sudoku_game.py e abra-o no seu editor de texto ou ambiente de desenvolvimento integrado (IDE) preferido.
cd ~/project
touch sudoku_game.py
Importar as Bibliotecas Necessárias
Importe as bibliotecas necessárias no início do arquivo. Precisamos das bibliotecas pygame e random para este jogo.
import pygame
import random
Instale a biblioteca pygame usando o comando pip.
sudo pip install pygame
Inicializar PyGame
Inicialize a biblioteca Pygame para configurar a janela do jogo.
pygame.init()
Definir Cores
Defina as cores a serem usadas no jogo. Usaremos o formato RGB para as cores.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
BLUE = (0, 0, 255)
LIGHT_BLUE = (100, 100, 255)
Definir Dimensões e Título da Janela do Jogo
Defina as dimensões da janela do jogo e defina um título para o jogo.
WINDOW_SIZE = (550, 550)
CELL_SIZE = WINDOW_SIZE[0] // 9
pygame.display.set_caption("Sudoku Game")
Criar a Janela do Jogo
Crie a janela do jogo usando as dimensões especificadas.
screen = pygame.display.set_mode(WINDOW_SIZE)
Carregar Fontes
Precisaremos carregar fontes para exibir números na tela do jogo. Carregue duas fontes, uma para os números maiores e outra para os números menores.
font_large = pygame.font.SysFont("calibri", 50)
font_small = pygame.font.SysFont("calibri", 30)
Gerar Grelha de Sudoku
Crie uma função generate_sudoku(difficulty) que gera uma nova grelha de Sudoku do nível de dificuldade especificado. A função deve retornar a grelha gerada.
def generate_sudoku(difficulty):
## Function code goes here
pass
Preencher Subgrelhas Diagonais
Dentro da função generate_sudoku, preencha as sub-grelhas diagonais da grelha com números aleatórios. Isso garante que cada sub-grelha contenha números de 1 a 9 sem repetição.
## 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]
Resolver Grelha de Sudoku
Crie uma função solve_sudoku(grid) que resolve a grelha de Sudoku usando o algoritmo de backtracking. A função deve retornar True se a grelha for solucionável e False caso contrário.
def solve_sudoku(grid):
## Function code goes here
pass
Encontrar Célula Vazia
Dentro da função solve_sudoku, crie uma função auxiliar find_empty_cell(grid) que retorna as coordenadas da próxima célula vazia na grelha. Se não houver células vazias, retorne 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
Verificar Movimento Válido
Dentro da função solve_sudoku, crie uma função auxiliar is_valid_move(grid, row, col, num) que verifica se colocar um número em uma célula é um movimento válido. A função deve retornar True se o movimento for válido e False caso contrário.
def is_valid_move(grid, row, col, num):
## Function code goes here
pass
Resolver a Grelha de Sudoku (Continuação)
Dentro da função solve_sudoku, use as funções auxiliares find_empty_cell e is_valid_move para implementar o algoritmo de backtracking (retrocesso). Se uma solução for encontrada, retorne True. Se o número atual levar a uma solução inválida, faça o retrocesso (backtrack) definindo a célula atual como 0.
## Tente preencher a célula vazia com números de 1 a 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
## Se o número atual levar a uma solução inválida, faça o retrocesso
grid[row][col] = 0
return False
Remover Números com Base na Dificuldade
Dentro da função generate_sudoku, remova números da grelha com base no nível de dificuldade especificado. Os níveis de dificuldade são: 1 (fácil), 2 (médio), 3 (difícil). O número de números a serem removidos é calculado como num_to_remove = 45 + 10 * difficulty.
## Remover números com base no nível de dificuldade
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
Desenhar a Grelha
Crie uma função draw_grid(grid, selected_cell) que desenha a grelha de Sudoku na janela do jogo. Esta função deve ser responsável por desenhar as células, os números e destacar a célula selecionada.
def draw_grid(grid, selected_cell):
## Código da função vai aqui
pass
Preencher Células e Desenhar Números
Dentro da função draw_grid, itere sobre a grelha e desenhe as células e os números usando as funções Pygame pygame.draw.rect e screen.blit.
## Desenhar as células
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)
## Desenhar os números
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)
Destacar Célula Selecionada
Dentro da função draw_grid, destaque a célula selecionada se ela não for None usando a função pygame.draw.rect.
## Destacar a célula selecionada
if (row, col) == selected_cell:
pygame.draw.rect(screen, LIGHT_BLUE, cell_rect, 3)
Desenhar Linhas da Grelha
Dentro da função draw_grid, desenhe as linhas para criar a grelha usando a função pygame.draw.line.
## Desenhar as linhas
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,
)
Atualizar a Exibição
Dentro da função draw_grid, atualize o display usando a função pygame.display.update.
pygame.display.update()
Verificar se a Grelha Está Cheia
Crie uma função is_grid_full(grid) que verifica se a grelha do Sudoku está completamente preenchida. Isso pode ser feito iterando sobre a grelha e verificando se alguma célula contém 0.
def is_grid_full(grid):
## Código da função vai aqui
pass
Obter Célula Sob o Mouse
Crie uma função get_cell_under_mouse(pos) que retorna as coordenadas da célula sob a posição do mouse. Isso pode ser calculado dividindo a posição do mouse pelo tamanho da célula.
def get_cell_under_mouse(pos):
## Código da função vai aqui
pass
Selecionar Dificuldade
Crie uma função select_difficulty() que permite ao jogador selecionar o nível de dificuldade antes de iniciar o jogo. Esta função deve exibir as opções de dificuldade e retornar o nível de dificuldade selecionado.
def select_difficulty():
## Código da função vai aqui
pass
Implementar Seleção de Dificuldade
Dentro da função select_difficulty, implemente a lógica de seleção de dificuldade usando as funções Pygame pygame.mouse.get_pos e pygame.event.get.
## Exibir texto de seleção de dificuldade
title_text = font_large.render("Select Difficulty", True, BLACK)
screen.blit(title_text, (110, 200))
## Exibir opções de dificuldade
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()
## Aguardar a seleção da dificuldade
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: ## Botão esquerdo do mouse
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
Loop Principal do Jogo
Crie o loop principal do jogo definindo uma função main().
def main():
## Código da função vai aqui
pass
Selecionar Dificuldade e Gerar Grade
Dentro da função main, selecione o nível de dificuldade chamando select_difficulty() e retorne se a dificuldade for None. Em seguida, gere uma grade de Sudoku usando o nível de dificuldade selecionado, chamando generate_sudoku(difficulty).
## Selecionar o nível de dificuldade
difficulty = select_difficulty()
if difficulty is None:
return
## Gerar uma nova grade de Sudoku
grid = generate_sudoku(difficulty)
Variáveis do Loop do Jogo
Dentro da função main, crie as variáveis do loop do jogo selected_cell e running. Defina selected_cell como None e running como True.
selected_cell = None
running = True
Habilitar Repetição de Teclas
Dentro da função main, habilite a repetição de teclas usando a função pygame.key.set_repeat. Definimos o atraso (delay) e o intervalo (interval) para 100 milissegundos para facilitar o preenchimento das células pelos jogadores.
## Habilitar repetição de teclas
pygame.key.set_repeat(100, 100)
Gerenciar Eventos
Dentro do loop do jogo, lide com eventos usando a função pygame.event.get. Verifique eventos de saída (quit events), eventos de botões do mouse (mouse button events) e eventos de teclas (key events).
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
Gerenciar Eventos de Botões do Mouse
Dentro do tratamento de eventos para eventos de botões do mouse, verifique se o botão esquerdo do mouse foi clicado ou se o botão direito do mouse foi clicado.
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
Gerenciar Clique do Botão Esquerdo do Mouse
Dentro do tratamento do clique do botão esquerdo do mouse, obtenha as coordenadas da célula sob a posição do mouse chamando get_cell_under_mouse(pos).
## Get the cell under the mouse position
pos = pygame.mouse.get_pos()
row, col = get_cell_under_mouse(pos)
Gerenciar Clique do Botão Esquerdo do Mouse (Continuação)
Dentro do tratamento do clique do botão esquerdo do mouse, selecione a célula se ela estiver vazia, verificando se grid[row][col] == 0.
## Select the cell if it's empty
if grid[row][col] == 0:
selected_cell = (row, col)
Gerenciar Clique do Botão Direito do Mouse
Dentro do tratamento do clique do botão direito do mouse, limpe a célula selecionada se ela não for None e estiver vazia, verificando se 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
Gerenciar Eventos de Tecla
Dentro do tratamento de eventos para eventos de tecla, verifique qual tecla numérica foi pressionada e defina o valor da célula selecionada de acordo.
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
Desenhar Grade e Verificar Conclusão
Dentro do loop do jogo, desenhe a grelha chamando draw_grid(grid, selected_cell). Em seguida, verifique se a grelha está completa chamando 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.")
Atualizar Exibição e Sair
Após o loop do jogo, atualize a exibição usando a função pygame.display.update e saia do jogo usando pygame.quit().
## Update the display
pygame.display.update()
## Quit the game
pygame.quit()
Executar o Jogo
Finalmente, adicione uma condição para verificar se o arquivo atual é o ponto de entrada principal do programa. Se for, execute o jogo chamando a função main().
if __name__ == "__main__":
main()
Execute o jogo usando o comando python.
python sudoku_game.py

Resumo
Parabéns! Você criou com sucesso um jogo de Sudoku usando Python e a biblioteca Pygame. O jogo permite que os jogadores selecionem um nível de dificuldade, preencham as células vazias com números e verifica se a grade está completa. Divirta-se jogando e resolvendo quebra-cabeças de Sudoku!



