cell.py
import pygame
class Cell:
def __init__(self, row, col, cell_size, c_id):
self.row = row
self.col = col
self.cell_size = cell_size
self.width = self.cell_size[0]
self.height = self.cell_size[1]
self.abs_x = row * self.width
self.abs_y = col * self.height
self.c_id = c_id
self.rect = pygame.Rect(
self.abs_x,
self.abs_y,
self.width,
self.height
)
self.occupying_piece = None
def draw(self, display):
pygame.draw.rect(display, (0,0,0), self.rect)
if self.occupying_piece != None and self.occupying_piece.p_id != 8:
centering_rect = self.occupying_piece.img.get_rect()
centering_rect.center = self.rect.center
display.blit(self.occupying_piece.img, centering_rect.topleft)
frame.py
import pygame
import random
from cell import Cell
from piece import Piece
class Frame:
def __init__(self, frame_size):
self.grid_size = 3
self.cell_width = frame_size // self.grid_size
self.cell_height = frame_size // self.grid_size
self.cell_size = (self.cell_width, self.cell_height)
self.grid = self._generate_cell()
self.pieces = self._generate_piece()
self._setup()
self.randomize_puzzle()
def _generate_cell(self):
cells = []
c_id = 0
for col in range(self.grid_size):
new_row = []
for row in range(self.grid_size):
new_row.append(Cell(row, col, self.cell_size, c_id))
c_id += 1
cells.append(new_row)
return cells
def _generate_piece(self):
puzzle_pieces = []
p_id = 0
for col in range(self.grid_size):
for row in range(self.grid_size):
puzzle_pieces.append(Piece(self.cell_size, p_id))
p_id += 1
return puzzle_pieces
def _setup(self):
for row in self.grid:
for cell in row:
tile_piece = self.pieces[-1]
cell.occupying_piece = tile_piece
self.pieces.remove(tile_piece)
def randomize_puzzle(self):
moves = [(0, 1),(0, -1),(1, 0),(-1, 0)]
for i in range(30):
shuffle_move = random.choice(moves)
for row in self.grid:
for cell in row:
tile_x = self.grid.index(row) + shuffle_move[0]
tile_y = row.index(cell) + shuffle_move[1]
if tile_x >= 0 and tile_x <= 2 and tile_y >= 0 and tile_y <= 2:
new_cell = self.grid[tile_x][tile_y]
if new_cell.occupying_piece.img == None:
c = (cell, new_cell)
try:
c[0].occupying_piece, c[1].occupying_piece = c[1].occupying_piece, c[0].occupying_piece
except:
return False
else:
continue
def _is_move_valid(self, click):
moves = {
79: (0, 1),
80: (0, -1),
81: (1, 0),
82: (-1, 0)
}
for row in self.grid:
for cell in row:
move = moves[click.scancode]
tile_x = self.grid.index(row) + move[0]
tile_y = row.index(cell) + move[1]
if tile_x >= 0 and tile_x <= 2 and tile_y >= 0 and tile_y <= 2:
new_cell = self.grid[tile_x][tile_y]
if new_cell.occupying_piece.img == None:
return (cell, new_cell)
else:
continue
def handle_click(self, click):
c = self._is_move_valid(click)
try:
c[0].occupying_piece, c[1].occupying_piece = c[1].occupying_piece, c[0].occupying_piece
except:
return False
def draw(self, display):
for row in self.grid:
for cell in row:
cell.draw(display)
game.py
import pygame
pygame.font.init()
class Game:
def __init__(self):
self.font = pygame.font.SysFont("Courier New", 35)
self.background_color = (255, 174, 66)
self.message_color = (17, 53, 165)
def arrow_key_clicked(self, click):
try:
if click.key == pygame.K_LEFT or click.key == pygame.K_RIGHT or click.key == pygame.K_UP or click.key == pygame.K_DOWN:
return(True)
except:
return(False)
def is_game_over(self, frame):
for row in frame.grid:
for cell in row:
piece_id = cell.occupying_piece.p_id
if cell.c_id == piece_id:
is_arranged = True
else:
is_arranged = False
break
return is_arranged
def message(self, screen):
screen.fill(self.background_color, (5, 460, 440, 35))
instructions = self.font.render('You Win!!', True, self.message_color)
screen.blit(instructions,(125,460))
main.py
import pygame
from frame import Frame
from game import Game
pygame.init()
pygame.font.init()
class Puzzle:
def __init__(self, screen):
self.screen = screen
self.running = True
self.FPS = pygame.time.Clock()
self.is_arranged = False
self.font = pygame.font.SysFont("Courier New", 33)
self.background_color = (255, 174, 66)
self.message_color = (17, 53, 165)
def _draw(self, frame):
frame.draw(self.screen)
pygame.display.update()
def _instruction(self):
instructions = self.font.render('Use Arrow Keys to Move', True, self.message_color)
screen.blit(instructions,(5,460))
def main(self, frame_size):
self.screen.fill("white")
frame = Frame(frame_size)
game = Game()
self._instruction()
while self.running:
if game.is_game_over(frame):
self.is_arranged = True
game.message(self.screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN:
if not self.is_arranged:
if game.arrow_key_clicked(event):
frame.handle_click(event)
self._draw(frame)
self.FPS.tick(30)
pygame.quit()
if __name__ == "__main__":
window_size = (450, 500)
screen = pygame.display.set_mode(window_size)
pygame.display.set_caption("Slide Puzzle")
game = Puzzle(screen)
game.main(window_size[0])
piece.py
import pygame
class Piece:
def __init__(self, piece_size, p_id):
self.piece_size = piece_size
self.p_id = p_id
if self.p_id != 8:
img_path = f'puzz-pieces/{self.p_id}.jpg'
self.img = pygame.image.load(img_path)
self.img = pygame.transform.scale(self.img, self.piece_size)
else:
self.img = None