Slide Puzzle Using Python PyGame

In this article, we will guide you through creating a slide puzzle game using Python and the PyGame library. A slide puzzle consists of numbered tiles in a grid with one empty space, where players slide tiles to arrange them in numerical order.

Throughout this tutorial, we will explore how to set up the game window, create puzzle tiles, shuffle them randomly, and handle user input for an interactive experience. By the end, you'll have a fully functional slide puzzle game.

Installation and Setup

First, install PyGame if you haven't already:

pip install pygame

Create a new Python script and import the necessary modules:

import pygame
import random
import sys

# Initialize PyGame
pygame.init()

# Game constants
WINDOW_SIZE = 400
GRID_SIZE = 3
TILE_SIZE = WINDOW_SIZE // GRID_SIZE
MARGIN = 2
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (70, 130, 180)

Creating the Game Window

Set up the game window with proper dimensions and title:

import pygame
import random
import sys

pygame.init()

WINDOW_SIZE = 400
GRID_SIZE = 3
TILE_SIZE = WINDOW_SIZE // GRID_SIZE
MARGIN = 2
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (70, 130, 180)

# Create game window
screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE))
pygame.display.set_caption("Slide Puzzle Game")
font = pygame.font.Font(None, 36)

print("Game window created successfully")
Game window created successfully

Puzzle Logic

Create the puzzle board representation and helper functions:

class SlidePuzzle:
    def __init__(self, size=3):
        self.size = size
        self.board = list(range(1, size * size)) + [0]  # 0 represents empty space
        self.solved_board = self.board.copy()
        
    def shuffle_board(self):
        """Shuffle the board to create a solvable puzzle"""
        for _ in range(1000):
            self.make_random_move()
    
    def find_empty_pos(self):
        """Find the position of empty space (0)"""
        index = self.board.index(0)
        return index // self.size, index % self.size
    
    def get_valid_moves(self):
        """Get list of tiles that can move into empty space"""
        empty_row, empty_col = self.find_empty_pos()
        moves = []
        
        # Check adjacent positions
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        for dr, dc in directions:
            new_row, new_col = empty_row + dr, empty_col + dc
            if 0 <= new_row < self.size and 0 <= new_col < self.size:
                moves.append((new_row, new_col))
        return moves
    
    def make_random_move(self):
        """Make a random valid move for shuffling"""
        valid_moves = self.get_valid_moves()
        if valid_moves:
            move_pos = random.choice(valid_moves)
            self.move_tile(move_pos[0], move_pos[1])
    
    def move_tile(self, row, col):
        """Move tile at given position to empty space"""
        empty_row, empty_col = self.find_empty_pos()
        tile_index = row * self.size + col
        empty_index = empty_row * self.size + empty_col
        
        # Swap tile with empty space
        self.board[tile_index], self.board[empty_index] = self.board[empty_index], self.board[tile_index]
    
    def is_solved(self):
        """Check if puzzle is solved"""
        return self.board == self.solved_board

# Test the puzzle logic
puzzle = SlidePuzzle(3)
print("Initial board:", puzzle.board)
puzzle.shuffle_board()
print("Shuffled board:", puzzle.board)
print("Is solved:", puzzle.is_solved())
Initial board: [1, 2, 3, 4, 5, 6, 7, 8, 0]
Shuffled board: [1, 2, 3, 4, 0, 6, 7, 5, 8]
Is solved: False

Complete Game Implementation

Here's the complete slide puzzle game with graphics and user interaction:

import pygame
import random
import sys

class SlidePuzzleGame:
    def __init__(self):
        pygame.init()
        self.WINDOW_SIZE = 400
        self.GRID_SIZE = 3
        self.TILE_SIZE = self.WINDOW_SIZE // self.GRID_SIZE
        self.MARGIN = 2
        
        # Colors
        self.WHITE = (255, 255, 255)
        self.BLACK = (0, 0, 0)
        self.BLUE = (70, 130, 180)
        self.GREEN = (60, 179, 113)
        self.GRAY = (128, 128, 128)
        
        # Setup display
        self.screen = pygame.display.set_mode((self.WINDOW_SIZE, self.WINDOW_SIZE))
        pygame.display.set_caption("Slide Puzzle Game")
        self.font = pygame.font.Font(None, 48)
        self.clock = pygame.time.Clock()
        
        # Initialize puzzle
        self.board = list(range(1, self.GRID_SIZE * self.GRID_SIZE)) + [0]
        self.solved_board = self.board.copy()
        self.shuffle_board()
        
    def shuffle_board(self):
        """Shuffle the board to create a solvable puzzle"""
        for _ in range(1000):
            self.make_random_move()
    
    def find_empty_pos(self):
        """Find the position of empty space (0)"""
        index = self.board.index(0)
        return index // self.GRID_SIZE, index % self.GRID_SIZE
    
    def get_valid_moves(self):
        """Get list of positions that can move into empty space"""
        empty_row, empty_col = self.find_empty_pos()
        moves = []
        
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        for dr, dc in directions:
            new_row, new_col = empty_row + dr, empty_col + dc
            if 0 <= new_row < self.GRID_SIZE and 0 <= new_col < self.GRID_SIZE:
                moves.append((new_row, new_col))
        return moves
    
    def make_random_move(self):
        """Make a random valid move for shuffling"""
        valid_moves = self.get_valid_moves()
        if valid_moves:
            move_pos = random.choice(valid_moves)
            self.move_tile(move_pos[0], move_pos[1])
    
    def move_tile(self, row, col):
        """Move tile at given position to empty space"""
        empty_row, empty_col = self.find_empty_pos()
        
        # Check if move is valid
        if (row, col) in self.get_valid_moves():
            tile_index = row * self.GRID_SIZE + col
            empty_index = empty_row * self.GRID_SIZE + empty_col
            self.board[tile_index], self.board[empty_index] = self.board[empty_index], self.board[tile_index]
            return True
        return False
    
    def is_solved(self):
        """Check if puzzle is solved"""
        return self.board == self.solved_board
    
    def get_tile_at_pos(self, mouse_pos):
        """Get tile position from mouse coordinates"""
        x, y = mouse_pos
        col = x // self.TILE_SIZE
        row = y // self.TILE_SIZE
        
        if 0 <= row < self.GRID_SIZE and 0 <= col < self.GRID_SIZE:
            return row, col
        return None
    
    def draw(self):
        """Draw the game board"""
        self.screen.fill(self.WHITE)
        
        for row in range(self.GRID_SIZE):
            for col in range(self.GRID_SIZE):
                index = row * self.GRID_SIZE + col
                tile_value = self.board[index]
                
                # Calculate tile position
                x = col * self.TILE_SIZE + self.MARGIN
                y = row * self.TILE_SIZE + self.MARGIN
                width = self.TILE_SIZE - 2 * self.MARGIN
                height = self.TILE_SIZE - 2 * self.MARGIN
                
                if tile_value != 0:  # Don't draw empty space
                    # Draw tile background
                    color = self.GREEN if self.is_solved() else self.BLUE
                    pygame.draw.rect(self.screen, color, (x, y, width, height))
                    pygame.draw.rect(self.screen, self.BLACK, (x, y, width, height), 2)
                    
                    # Draw tile number
                    text = self.font.render(str(tile_value), True, self.WHITE)
                    text_rect = text.get_rect(center=(x + width//2, y + height//2))
                    self.screen.blit(text, text_rect)
        
        # Draw win message
        if self.is_solved():
            text = self.font.render("Puzzle Solved!", True, self.BLACK)
            text_rect = text.get_rect(center=(self.WINDOW_SIZE//2, self.WINDOW_SIZE//2))
            pygame.draw.rect(self.screen, self.WHITE, text_rect.inflate(20, 10))
            self.screen.blit(text, text_rect)
        
        pygame.display.flip()
    
    def run(self):
        """Main game loop"""
        running = True
        
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:  # Left mouse button
                        tile_pos = self.get_tile_at_pos(event.pos)
                        if tile_pos:
                            row, col = tile_pos
                            self.move_tile(row, col)
                
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_r:  # Press 'R' to reset
                        self.board = list(range(1, self.GRID_SIZE * self.GRID_SIZE)) + [0]
                        self.shuffle_board()
            
            self.draw()
            self.clock.tick(60)
        
        pygame.quit()
        sys.exit()

# Run the game
if __name__ == "__main__":
    game = SlidePuzzleGame()
    game.run()

Game Controls

The game supports simple mouse controls:

  • Left Click: Click on any tile adjacent to the empty space to move it
  • Press 'R': Reset and shuffle the puzzle
  • Close Window: Exit the game

Key Features

Feature Description
Solvable Shuffling Ensures puzzle is always solvable by making random valid moves
Visual Feedback Tiles turn green when puzzle is solved
Input Validation Only allows valid moves adjacent to empty space
Reset Function Press 'R' to shuffle and start over

Conclusion

This slide puzzle game demonstrates fundamental PyGame concepts including event handling, graphics rendering, and game state management. The modular design makes it easy to modify grid size, colors, or add new features like move counters or timers.

Updated on: 2026-03-27T10:08:02+05:30

939 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements