Open In App

Building and visualizing Sudoku Game Using Pygame

Last Updated : 04 Sep, 2021
Comments
Improve
Suggest changes
Like Article
Like
Report

Sudoku is a logic-based, combinatorial number-placement puzzle. The objective is to fill a 9×9 grid with digits so that each column, each row, and each of the nine 3×3 subgrids that compose the grid contain all of the digits from 1 to 9. 

We will be building the Sudoku Game in python using pygame library and automate the game using backtracking algorithm. 

Features Implemented : 

  • Game Interface to Play
  • Auto solving
  • Visualization of auto solving i.e., Backtracking Algorithm visualization
  • Options: Reset, Clear game

Prerequisite :  

Implementation Steps :

 1. Fill the pygame window with Sudoku Board i.e., Construct a 9×9 grid. 
2. Fill the board with default numbers. 
3. Assign a specific key for each operations and listen it. 
4. Integrate the backtracking algorithm into it. 
5. Use set of colors to visualize auto solving.

Instruction:  

  • Press ‘Enter’ To Auto Solve and Visualize.
  • To play the game manually,
    Place the cursor in any cell you want and enter the number.
  • At any point, press enter to solve automatically.

Below is the Implementation :  

Python3

# import pygame library
import pygame
 
# initialise the pygame font
pygame.font.init()
 
# Total window
screen= pygame.display.set_mode((500,600))
 
# Title and Icon
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
# Default Sudoku Board.
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]
    ]
 
# Load test fonts for future use
font1= pygame.font.SysFont("comicsans",40)
font2= pygame.font.SysFont("comicsans",20)
def get_cord(pos):
    global x
    x= pos[0]//dif
    global y
    y= pos[1]//dif
 
# Highlight the cell selected
def draw_box():
    for iin 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)  
 
# Function to draw required lines for making Sudoku grid        
def draw():
    # Draw the lines
        
    for iin range (9):
        for jin range (9):
            if grid[i][j]!= 0:
 
                # Fill blue color in already numbered grid
                pygame.draw.rect(screen, (0,153,153), (i* dif, j* dif, dif+ 1, dif+ 1))
 
                # Fill grid with default numbers specified
                text1= font1.render(str(grid[i][j]),1, (0,0,0))
                screen.blit(text1, (i* dif+ 15, j* dif+ 15))
    # Draw lines horizontally and verticallyto form grid          
    for iin 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)     
 
# Fill value entered in cell     
def draw_val(val):
    text1= font1.render(str(val),1, (0,0,0))
    screen.blit(text1, (x* dif+ 15, y* dif+ 15))   
 
# Raise error when wrong value entered
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)) 
 
# Check if the value entered in board is valid
def valid(m, i, j, val):
    for itin range(9):
        if m[i][it]== val:
            return False
        if m[it][j]== val:
            return False
    it= i//3
    jt= j//3
    for iin range(it* 3, it* 3 + 3):
        for jin range (jt* 3, jt* 3 + 3):
            if m[i][j]== val:
                return False
    return True
 
# Solves the sudoku board using Backtracking Algorithm
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 itin range(1,10):
        if valid(grid, i, j, it)== True:
            grid[i][j]= it
            global x, y
            x= i
            y= j
            # white color background\
            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
            # white color background\
            screen.fill((255,255,255))
         
            draw()
            draw_box()
            pygame.display.update()
            pygame.time.delay(50)   
    return False 
 
# Display instruction for the game
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))
 
# Display options when solved
def result():
    text1= font1.render("FINISHED PRESS R or D",1, (0,0,0))
    screen.blit(text1, (20,570))   
run= True
flag1= 0
flag2= 0
rs= 0
error= 0
# The loop thats keep the window running
while run:
     
    # White color background
    screen.fill((255,255,255))
    # Loop through the events stored in event.get()
    for eventin pygame.event.get():
        # Quit the game window
        if event.type == pygame.QUIT:
            run= False 
        # Get the mouse position to insert number   
        if event.type == pygame.MOUSEBUTTONDOWN:
            flag1= 1
            pos= pygame.mouse.get_pos()
            get_cord(pos)
        # Get the number to be inserted if key pressed   
        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  
            # If R pressed clear the sudoku board
            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]
                ]
            # If D is pressed reset the board to default
            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)
        # print(x)
        # print(y)
        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()   
 
    # Update window
    pygame.display.update() 
 
# Quit pygame window   
pygame.quit()    
    

Output:


 



Next Article

Similar Reads