Desarrollo de un juego de Sudoku con Python y Pygame

PythonPythonIntermediate
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este proyecto, crearemos un juego de Sudoku utilizando Python y la librería Pygame. El juego generará una cuadrícula de Sudoku con un nivel de dificultad especificado y permitirá a los jugadores resolver el rompecabezas llenando las celdas vacías con números. El juego ofrecerá características como la selección de dificultad, la resaltación de las celdas seleccionadas y la comprobación de si la cuadrícula está completa.

👀 Vista previa

Vista previa del juego de Sudoku

🎯 Tareas

En este proyecto, aprenderás:

  • Cómo importar las bibliotecas necesarias
  • Cómo inicializar PyGame
  • Cómo definir colores
  • Cómo establecer las dimensiones y el título de la ventana del juego
  • Cómo crear la ventana del juego
  • Cómo cargar fuentes
  • Cómo generar una cuadrícula de Sudoku
  • Cómo resolver una cuadrícula de Sudoku utilizando el algoritmo de retroceso
  • Cómo eliminar números de la cuadrícula según la dificultad
  • Cómo dibujar la cuadrícula de Sudoku en la ventana del juego
  • Cómo comprobar si la cuadrícula está completamente llena
  • Cómo obtener las coordenadas de la celda debajo de la posición del mouse
  • Cómo seleccionar el nivel de dificultad
  • Cómo implementar el bucle principal del juego

🏆 Logros

Después de completar este proyecto, podrás:

  • Utilizar la librería Pygame para el desarrollo de juegos en Python
  • Generar una cuadrícula de Sudoku con un nivel de dificultad especificado
  • Resolver una cuadrícula de Sudoku utilizando el algoritmo de retroceso
  • Manejar eventos del mouse y el teclado en Pygame
  • Dibujar formas y texto en la ventana del juego
  • Implementar el bucle principal del juego en Pygame

Crear los archivos del proyecto

Para comenzar, crea un archivo llamado sudoku_game.py y dile que lo abra en tu editor de texto o entorno de desarrollo integrado (IDE) preferido.

cd ~/proyecto
touch sudoku_game.py
✨ Revisar Solución y Practicar

Importar las bibliotecas necesarias

Importa las bibliotecas necesarias al principio del archivo. Necesitamos las bibliotecas pygame y random para este juego.

import pygame
import random

Instala la biblioteca pygame utilizando el comando pip.

sudo pip install pygame
✨ Revisar Solución y Practicar

Inicializar PyGame

Inicializa la librería PyGame para configurar la ventana del juego.

pygame.init()
✨ Revisar Solución y Practicar

Definir los colores

Define los colores que se utilizarán en el juego. Utilizaremos el formato RGB para los colores.

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (200, 200, 200)
BLUE = (0, 0, 255)
LIGHT_BLUE = (100, 100, 255)
✨ Revisar Solución y Practicar

Establecer las dimensiones de la ventana del juego y el título

Establece las dimensiones de la ventana del juego y asigna un título al juego.

WINDOW_SIZE = (550, 550)
CELL_SIZE = WINDOW_SIZE[0] // 9

pygame.display.set_caption("Sudoku Game")
✨ Revisar Solución y Practicar

Crear la ventana del juego

Crea la ventana del juego utilizando las dimensiones especificadas.

screen = pygame.display.set_mode(WINDOW_SIZE)
✨ Revisar Solución y Practicar

Cargar fuentes

Necesitaremos cargar fuentes para mostrar números en la pantalla del juego. Carga dos fuentes, una para los números más grandes y otra para los números más pequeños.

font_large = pygame.font.SysFont("calibri", 50)
font_small = pygame.font.SysFont("calibri", 30)
✨ Revisar Solución y Practicar

Generar la cuadrícula de Sudoku

Crea una función generate_sudoku(difficulty) que genere una nueva cuadrícula de Sudoku del nivel de dificultad especificado. La función debe devolver la cuadrícula generada.

def generate_sudoku(difficulty):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Llenar las subcuadrículas diagonales

Dentro de la función generate_sudoku, llena las subcuadrículas diagonales de la cuadrícula con números aleatorios. Esto asegura que cada subcuadrícula contenga números del 1 al 9 sin repetición.

## Llenar las subcuadrículas diagonales
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]
✨ Revisar Solución y Practicar

Resolver la cuadrícula de Sudoku

Crea una función solve_sudoku(grid) que resuelva la cuadrícula de Sudoku utilizando el algoritmo de retroceso. La función debe devolver True si la cuadrícula es resoluble y False en caso contrario.

def solve_sudoku(grid):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Encontrar la celda vacía

Dentro de la función solve_sudoku, crea una función auxiliar find_empty_cell(grid) que devuelva las coordenadas de la siguiente celda vacía en la cuadrícula. Si no hay celdas vacías, devuelve 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
✨ Revisar Solución y Practicar

Verificar si el movimiento es válido

Dentro de la función solve_sudoku, crea una función auxiliar is_valid_move(grid, row, col, num) que verifique si colocar un número en una celda es un movimiento válido. La función debe devolver True si el movimiento es válido y False en caso contrario.

def is_valid_move(grid, row, col, num):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Resolver la cuadrícula de Sudoku (continuación)

Dentro de la función solve_sudoku, utiliza las funciones auxiliares find_empty_cell e is_valid_move para implementar el algoritmo de retroceso. Si se encuentra una solución, devuelve True. Si el número actual conduce a una solución no válida, retrocede estableciendo la celda actual en 0.

## Intenta llenar la celda vacía con números del 1 al 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

        ## Si el número actual conduce a una solución no válida, retrocede
        grid[row][col] = 0

return False
✨ Revisar Solución y Practicar

Eliminar números según la dificultad

Dentro de la función generate_sudoku, elimina números de la cuadrícula según el nivel de dificultad especificado. Los niveles de dificultad son: 1 (fácil), 2 (medio), 3 (difícil). La cantidad de números a eliminar se calcula como num_to_remove = 45 + 10 * difficulty.

## Elimina números según el nivel de dificultad
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
✨ Revisar Solución y Practicar

Dibujar la cuadrícula

Crea una función draw_grid(grid, selected_cell) que dibuje la cuadrícula de Sudoku en la ventana del juego. Esta función debe ser responsable de dibujar las celdas, los números y resaltar la celda seleccionada.

def draw_grid(grid, selected_cell):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Rellenar celdas y dibujar números

Dentro de la función draw_grid, recorre la cuadrícula y dibuja las celdas y los números utilizando las funciones de Pygame pygame.draw.rect y screen.blit.

## Dibuja las celdas
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)

        ## Dibuja los 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)
✨ Revisar Solución y Practicar

Resaltar la celda seleccionada

Dentro de la función draw_grid, resalta la celda seleccionada si no es None utilizando la función pygame.draw.rect.

## Resalta la celda seleccionada
if (row, col) == selected_cell:
    pygame.draw.rect(screen, LIGHT_BLUE, cell_rect, 3)
✨ Revisar Solución y Practicar

Dibujar líneas de la cuadrícula

Dentro de la función draw_grid, dibuja las líneas para crear la cuadrícula utilizando la función pygame.draw.line.

## Dibuja las líneas
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,
    )
✨ Revisar Solución y Practicar

Actualizar la pantalla

Dentro de la función draw_grid, actualiza la pantalla utilizando la función pygame.display.update.

pygame.display.update()
✨ Revisar Solución y Practicar

Comprobar si la cuadrícula está completa

Crea una función is_grid_full(grid) que comprueba si la cuadrícula de Sudoku está completamente llena. Esto se puede hacer recorriendo la cuadrícula y comprobando si alguna celda contiene 0.

def is_grid_full(grid):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Obtener la celda debajo del cursor del mouse

Crea una función get_cell_under_mouse(pos) que devuelva las coordenadas de la celda ubicada debajo de la posición del cursor del mouse. Esto se puede calcular dividiendo la posición del mouse por el tamaño de la celda.

def get_cell_under_mouse(pos):
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Seleccionar dificultad

Crea una función select_difficulty() que permita al jugador seleccionar el nivel de dificultad antes de comenzar el juego. Esta función debe mostrar las opciones de dificultad y devolver el nivel de dificultad seleccionado.

def select_difficulty():
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Implementar la selección de dificultad

Dentro de la función select_difficulty, implementa la lógica de selección de dificultad utilizando las funciones de Pygame pygame.mouse.get_pos y pygame.event.get.

## Mostrar el texto de selección de dificultad
title_text = font_large.render("Select Difficulty", True, BLACK)
screen.blit(title_text, (110, 200))

## Mostrar las opciones de dificultad
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()

## Esperar a que se seleccione la dificultad
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ón izquierdo del 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
✨ Revisar Solución y Practicar

Bucle principal del juego

Crea el bucle principal del juego definiendo una función main().

def main():
    ## Código de la función va aquí
    pass
✨ Revisar Solución y Practicar

Seleccionar dificultad y generar la cuadrícula

Dentro de la función main, selecciona el nivel de dificultad llamando a select_difficulty() y devuelve si la dificultad es None. Luego, genera una cuadrícula de Sudoku utilizando el nivel de dificultad seleccionado llamando a generate_sudoku(difficulty).

## Selecciona el nivel de dificultad
difficulty = select_difficulty()
if difficulty is None:
    return

## Genera una nueva cuadrícula de Sudoku
grid = generate_sudoku(difficulty)
✨ Revisar Solución y Practicar

Variables del bucle del juego

Dentro de la función main, crea las variables del bucle del juego selected_cell y running. Establece selected_cell en None y running en True.

selected_cell = None
running = True
✨ Revisar Solución y Practicar

Habilitar la repetición de teclas

Dentro de la función main, habilita la repetición de teclas utilizando la función pygame.key.set_repeat. Establecemos el retraso y el intervalo en 100 milisegundos para que sea más fácil para los jugadores rellenar las celdas.

## Habilitar la repetición de teclas
pygame.key.set_repeat(100, 100)
✨ Revisar Solución y Practicar

Manejar eventos

Dentro del bucle del juego, maneja los eventos utilizando la función pygame.event.get. Verifica eventos de salida, eventos de botones del mouse y eventos de teclado.

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    elif event.type == pygame.MOUSEBUTTONDOWN:
        ## Manejar eventos de botones del mouse
        pass
    elif event.type == pygame.KEYDOWN:
        ## Manejar eventos de teclado
        pass
✨ Revisar Solución y Practicar

Manejar eventos de botones del mouse

Dentro del manejo de eventos de botones del mouse, verifica si se hizo clic en el botón izquierdo o en el botón derecho del mouse.

if event.button == 1:  ## Botón izquierdo del mouse
    ## Manejar clic en el botón izquierdo del mouse
    pass
elif event.button == 3:  ## Botón derecho del mouse
    ## Manejar clic en el botón derecho del mouse
    pass
✨ Revisar Solución y Practicar

Manejar clic en el botón izquierdo del mouse

Dentro del manejo del clic en el botón izquierdo del mouse, obtén las coordenadas de la celda debajo de la posición del mouse llamando a get_cell_under_mouse(pos).

## Obtener la celda debajo de la posición del mouse
pos = pygame.mouse.get_pos()
row, col = get_cell_under_mouse(pos)
✨ Revisar Solución y Practicar

Manejar clic en el botón izquierdo del mouse (continuación)

Dentro del manejo del clic en el botón izquierdo del mouse, selecciona la celda si está vacía verificando si grid[row][col] == 0.

## Selecciona la celda si está vacía
if grid[row][col] == 0:
    selected_cell = (row, col)
✨ Revisar Solución y Practicar

Manejar clic en el botón derecho del mouse

Dentro del manejo del clic en el botón derecho del mouse, limpia la celda seleccionada si no es None y está vacía verificando si grid[selected_cell[0]][selected_cell[1]] == 0.

if selected_cell:
    ## Limpia la celda seleccionada si está vacía
    if grid[selected_cell[0]][selected_cell[1]] == 0:
        grid[selected_cell[0]][selected_cell[1]] = 0
✨ Revisar Solución y Practicar

Manejar eventos de teclado

Dentro del manejo de eventos de teclado, verifica qué tecla numérica se presionó y establece el valor de la celda seleccionada en consecuencia.

if selected_cell:
    ## Obtener la tecla presionada
    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
✨ Revisar Solución y Practicar

Dibujar la cuadrícula y comprobar la finalización

Dentro del bucle principal del juego, dibuja la cuadrícula llamando a draw_grid(grid, selected_cell). Luego, comprueba si la cuadrícula está completa llamando a is_grid_full(grid).

## Dibujar la cuadrícula
draw_grid(grid, selected_cell)

## Comprobar si la cuadrícula está completa
if is_grid_full(grid):
    print("¡Felicitaciones! Has resuelto el rompecabezas del Sudoku.")
✨ Revisar Solución y Practicar

Actualizar la pantalla y salir

Después del bucle principal del juego, actualiza la pantalla usando la función pygame.display.update y sale del juego usando pygame.quit().

## Actualizar la pantalla
pygame.display.update()

## Salir del juego
pygame.quit()
✨ Revisar Solución y Practicar

Ejecutar el juego

Finalmente, agrega una condición para comprobar si el archivo actual es el punto de entrada principal del programa. Si es así, ejecuta el juego llamando a la función main().

if __name__ == "__main__":
    main()

Ejecuta el juego usando el comando python.

python sudoku_game.py
Captura de pantalla de la ejecución del juego del Sudoku
✨ Revisar Solución y Practicar

Resumen

¡Felicitaciones! Has creado con éxito un juego de Sudoku usando Python y la biblioteca Pygame. El juego permite a los jugadores seleccionar un nivel de dificultad, rellenar las celdas vacías con números y comprueba si la cuadrícula está completa. ¡Que te diviertas jugando y resolviendo rompecabezas de Sudoku!