Xây dựng và trực quan hóa trò chơi Sudoku bằng Pygame

Category: Pygame

Sudoku là một trò chơi giải đố sắp xếp số dựa trên logic, kết hợp. Mục tiêu là điền các chữ số vào lưới 9x9 sao cho mỗi cột, mỗi hàng và mỗi ô lưới con 3x3 tạo nên lưới đều chứa tất cả các chữ số từ 1 đến 9. 

Chúng tôi sẽ xây dựng trò chơi Sudoku bằng Python sử dụng thư viện pygame và tự động hóa trò chơi bằng thuật toán quay lui. 

Các tính năng đã triển khai: 

  • Giao diện trò chơi để chơi

  • Tự động giải quyết

  • Hình ảnh hóa giải pháp tự động tức là hình ảnh hóa thuật toán quay lui

  • Tùy chọn: Đặt lại, Xóa trò chơi

Điều kiện tiên quyết:  

  • Thư viện Pygame phải được cài đặt sẵn

  • Kiến thức về thuật toán quay lui

Các bước thực hiện:

 1. Điền bảng Sudoku vào cửa sổ PyGame, ví dụ: Xây dựng một lưới 9x9. 
2. Điền các số mặc định vào bảng. 
3. Gán một phím cụ thể cho mỗi phép tính và lắng nghe. 
4. Tích hợp thuật toán quay lui vào đó. 
5. Sử dụng bộ màu để trực quan hóa quá trình giải tự động.

Chỉ dẫn:  

  • Nhấn 'Enter' để tự động giải và trực quan hóa.

  • Để chơi trò chơi theo cách thủ công,
    hãy đặt con trỏ vào bất kỳ ô nào bạn muốn và nhập số.

  • Bất cứ lúc nào, nhấn Enter để giải tự động.

Dưới đây là phần triển khai:  

# nhập thư viện pygame
import pygame

# khởi tạo font trong pygame
pygame.font.init()

# Cửa sổ tổng
screen = pygame.display.set_mode((500, 600))

# Tiêu đề và biểu tượng
pygame.display.set_caption("SUDOKU SOLVER USING BACKTRACKING")
img = pygame.image.load('icon.png')
pygame.display.set_icon(img)

x = 0
y = 0
dif = 500 / 9
val = 0
# Bảng Sudoku mặc định.
grid =[
        [7, 8, 0, 4, 0, 0, 1, 2, 0],
        [6, 0, 0, 0, 7, 5, 0, 0, 9],
        [0, 0, 0, 6, 0, 1, 0, 7, 8],
        [0, 0, 7, 0, 4, 0, 2, 6, 0],
        [0, 0, 1, 0, 5, 0, 9, 3, 0],
        [9, 0, 4, 0, 6, 0, 0, 0, 5],
        [0, 7, 0, 3, 0, 0, 0, 1, 2],
        [1, 2, 0, 0, 0, 7, 4, 0, 0],
        [0, 4, 9, 2, 0, 6, 0, 0, 7]
    ]

# Tải font để dùng sau này
font1 = pygame.font.SysFont("comicsans", 40)
font2 = pygame.font.SysFont("comicsans", 20)

# Lấy tọa độ chuột
def get_cord(pos):
    global x
    x = pos[0]//dif
    global y
    y = pos[1]//dif

# Tô ô được chọn
def draw_box():
    for i in range(2):
        pygame.draw.line(screen, (255, 0, 0), (x * dif-3, (y + i)*dif), (x * dif + dif + 3, (y + i)*dif), 7)
        pygame.draw.line(screen, (255, 0, 0), ( (x + i)* dif, y * dif ), ((x + i) * dif, y * dif + dif), 7)   

# Vẽ các đường tạo lưới Sudoku
def draw():
    # Vẽ các đường kẻ
    for i in range (9):
        for j in range (9):
            if grid[i][j]!= 0:

                # Tô màu xanh lam vào ô đã có số
                pygame.draw.rect(screen, (0, 153, 153), (i * dif, j * dif, dif + 1, dif + 1))

                # Hiển thị các số mặc định trên bảng
                text1 = font1.render(str(grid[i][j]), 1, (0, 0, 0))
                screen.blit(text1, (i * dif + 15, j * dif + 15))

    # Vẽ đường ngang và dọc để tạo lưới
    for i in range(10):
        if i % 3 == 0 :
            thick = 7
        else:
            thick = 1
        pygame.draw.line(screen, (0, 0, 0), (0, i * dif), (500, i * dif), thick)
        pygame.draw.line(screen, (0, 0, 0), (i * dif, 0), (i * dif, 500), thick)      

# Hiển thị giá trị vừa nhập
def draw_val(val):
    text1 = font1.render(str(val), 1, (0, 0, 0))
    screen.blit(text1, (x * dif + 15, y * dif + 15))    

# Hiện lỗi khi nhập sai giá trị
def raise_error1():
    text1 = font1.render("WRONG !!!", 1, (0, 0, 0))
    screen.blit(text1, (20, 570))  
def raise_error2():
    text1 = font1.render("Wrong !!! Not a valid Key", 1, (0, 0, 0))
    screen.blit(text1, (20, 570))  

# Kiểm tra giá trị nhập vào có hợp lệ không
def valid(m, i, j, val):
    for it in range(9):
        if m[i][it]== val:
            return False
        if m[it][j]== val:
            return False
    it = i//3
    jt = j//3
    for i in range(it * 3, it * 3 + 3):
        for j in range (jt * 3, jt * 3 + 3):
            if m[i][j]== val:
                return False
    return True

# Giải sudoku bằng thuật toán quay lui (Backtracking)
def solve(grid, i, j):
    while grid[i][j]!= 0:
        if i<8:
            i+= 1
        elif i == 8 and j<8:
            i = 0
            j+= 1
        elif i == 8 and j == 8:
            return True
    pygame.event.pump()    
    for it in range(1, 10):
        if valid(grid, i, j, it)== True:
            grid[i][j]= it
            global x, y
            x = i
            y = j
            # nền trắng
            screen.fill((255, 255, 255))
            draw()
            draw_box()
            pygame.display.update()
            pygame.time.delay(20)
            if solve(grid, i, j)== 1:
                return True
            else:
                grid[i][j]= 0
            # nền trắng
            screen.fill((255, 255, 255))
            draw()
            draw_box()
            pygame.display.update()
            pygame.time.delay(50)    
    return False  

# Hiển thị hướng dẫn chơi
def instruction():
    text1 = font2.render("PRESS D TO RESET TO DEFAULT / R TO EMPTY", 1, (0, 0, 0))
    text2 = font2.render("ENTER VALUES AND PRESS ENTER TO VISUALIZE", 1, (0, 0, 0))
    screen.blit(text1, (20, 520))        
    screen.blit(text2, (20, 540))

# Hiển thị kết quả khi hoàn thành
def result():
    text1 = font1.render("FINISHED PRESS R or D", 1, (0, 0, 0))
    screen.blit(text1, (20, 570))    

# Vòng lặp chính chạy cửa sổ trò chơi
run = True
flag1 = 0
flag2 = 0
rs = 0
error = 0
while run:
    
    # nền trắng
    screen.fill((255, 255, 255))

    # Duyệt qua các sự kiện
    for event in pygame.event.get():
        # Thoát cửa sổ
        if event.type == pygame.QUIT:
            run = False  

        # Lấy tọa độ chuột để nhập số    
        if event.type == pygame.MOUSEBUTTONDOWN:
            flag1 = 1
            pos = pygame.mouse.get_pos()
            get_cord(pos)

        # Lấy số được nhập nếu nhấn phím    
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x-= 1
                flag1 = 1
            if event.key == pygame.K_RIGHT:
                x+= 1
                flag1 = 1
            if event.key == pygame.K_UP:
                y-= 1
                flag1 = 1
            if event.key == pygame.K_DOWN:
                y+= 1
                flag1 = 1    
            if event.key == pygame.K_1:
                val = 1
            if event.key == pygame.K_2:
                val = 2    
            if event.key == pygame.K_3:
                val = 3
            if event.key == pygame.K_4:
                val = 4
            if event.key == pygame.K_5:
                val = 5
            if event.key == pygame.K_6:
                val = 6 
            if event.key == pygame.K_7:
                val = 7
            if event.key == pygame.K_8:
                val = 8
            if event.key == pygame.K_9:
                val = 9  
            if event.key == pygame.K_RETURN:
                flag2 = 1   

            # Nếu nhấn R thì xóa bảng sudoku
            if event.key == pygame.K_r:
                rs = 0
                error = 0
                flag2 = 0
                grid =[
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
                ]

            # Nếu nhấn D thì đặt lại bảng về mặc định 
            if event.key == pygame.K_d:
                rs = 0
                error = 0
                flag2 = 0
                grid =[
                    [7, 8, 0, 4, 0, 0, 1, 2, 0],
                    [6, 0, 0, 0, 7, 5, 0, 0, 9],
                    [0, 0, 0, 6, 0, 1, 0, 7, 8],
                    [0, 0, 7, 0, 4, 0, 2, 6, 0],
                    [0, 0, 1, 0, 5, 0, 9, 3, 0],
                    [9, 0, 4, 0, 6, 0, 0, 0, 5],
                    [0, 7, 0, 3, 0, 0, 0, 1, 2],
                    [1, 2, 0, 0, 0, 7, 4, 0, 0],
                    [0, 4, 9, 2, 0, 6, 0, 0, 7]
                ]

    if flag2 == 1:
        if solve(grid, 0, 0)== False:
            error = 1
        else:
            rs = 1
        flag2 = 0    

    if val != 0:            
        draw_val(val)
        if valid(grid, int(x), int(y), val)== True:
            grid[int(x)][int(y)]= val
            flag1 = 0
        else:
            grid[int(x)][int(y)]= 0
            raise_error2()   
        val = 0    

    if error == 1:
        raise_error1()  
    if rs == 1:
        result()        
    draw()  
    if flag1 == 1:
        draw_box()       
    instruction()    

    # Cập nhật cửa sổ
    pygame.display.update()  

# Thoát cửa sổ pygame    
pygame.quit()

Đầu ra:

Published on Jul 28, 2025

Related Posts

Trò chơi 8-bit sử dụng pygame

Pygame là một thư viện Python chuyên dụng để thiết kế và xây dựng trò chơi. Pygame chỉ hỗ trợ các trò chơi 2D được xây dựng bằng các sprite khác nhau....

Pygame