Sliding Tile Puzzle in Python
Sliding tiles game also known as sliding puzzle or sliding blocks game. In this game, the player has to arrange the tiles or blocks in the correct order.
About Sliding Tiles Puzzle Python Project
The objective of this project is to create a sliding tile game of multiple levels. In this game, the player has to select level which he/she wants to play. Now, he can start playing the game by clicking on the tile which they want to move.
Project Prerequisites
This sliding tile game python project is build using pygame, random, sys, os module, and with concepts of python.
- Pygame module is used to build gaming or multimedia type application
- Random module is used to generate numbers randomly
Download Code of Sliding Tile Game Python Project
Please download the source code of sliding tile puzzle: Sliding Tile in Python
Project File Structure
To build this project we follow the below steps:
- Importing required modules
- Initializing and creating game window
- Creating class for main concept of game
- Defining function
- Creating levels
- Mainloop
Lets start building sliding tiles game
1. Importing required modules
import pygame import sys, os, random
In this step, we import the required modules.
2. Initializing window
#initializing window WIDTH = 800 HEIGHT = 600 FPS = 12 pygame.init() pygame.display.set_caption('sliding tiles- TechVivdan') gameDisplay = pygame.display.set_mode((WIDTH, HEIGHT)) clock = pygame.time.Clock() # Define colors WHITE = (255,255,255) BLACK = (0,0,0) RED = (255,0,0) brown = (100,40,0) background = pygame.image.load('white.jpg') background = pygame.transform.scale(background, (800, 600)) font = pygame.font.Font(os.path.join(os.getcwd(), 'comic.ttf'), 70)
- pygame.init() used to initialize pygame
- pygame.display.set_caption used to set the caption of the game window
- FPS used to controls how the gameDisplay should refresh.
- WIDTH and HEIGHT store the width and height of the game window
- The width and height of the window are set by using pygame.display.set_mode
- pygame.image.load is used to set image
- pygame.transform.scale is used to scale image according to the requirement
3. Creating the main concept behind the game
class Generate_Puzzle: def __init__(self, gridsize, tilesize, margin): self.gridsize,self.tilesize,self.margin = gridsize, tilesize, margin self.tiles_no = gridsize[0]*gridsize[1]-1 # no of tiles self.tiles = [(x,y) for y in range(gridsize[1]) for x in range(gridsize[0])] #coordinate of tiles self.tilepos = {(x,y):(x*(tilesize+margin)+margin,y*(tilesize+margin)+margin) for y in range(gridsize[1]) for x in range(gridsize[0])} #tile position self.prev = None self.tile_images =[] font = pygame.font.Font(None, 80) for i in range(self.tiles_no): image = pygame.Surface((tilesize,tilesize)) #display tiles image.fill(brown) text = font.render(str(i+1),2,(255,255,255)) ##text on tiles width,height = text.get_size() #text size image.blit(text,((tilesize-width)/2 , (tilesize-height)/2)) #####display text in the middle of tile self.tile_images += [image] def Blank_pos(self): return self.tiles[-1] def set_Blank_pos(self,pos): self.tiles[-1] = pos opentile = property(Blank_pos, set_Blank_pos) #get and set the pos of blank def switch_tile(self, tile): self.tiles[self.tiles.index(tile)]=self.opentile self.opentile = tile self.prev= self.opentile def check_in_grid(self, tile): return tile[0]>=0 and tile[0]<self.gridsize[0] and tile[1]>=0 and tile[1]<self.gridsize[1] def close_to(self): #adjacent tile postion to blank (which tiles can move to blank position) x, y = self.opentile return (x-1,y),(x+1,y),(x,y-1),(x,y+1) def set_tile_randomly(self): adj = self.close_to() adj = [pos for pos in adj if self.check_in_grid(pos)and pos!= self.prev ] tile = random.choice(adj) self.switch_tile(tile) #print(self.prev) def update_tile_pos(self,dt): #update tile position mouse = pygame.mouse.get_pressed() mpos = pygame.mouse.get_pos() if mouse[0]: x,y = mpos[0]%(self.tilesize+self.margin),mpos[1]%(self.tilesize+self.margin) if x>self.margin and y>self.margin: tile = mpos[0]//self.tilesize,mpos[1]//self.tilesize if self.check_in_grid(tile) and tile in self.close_to(): self.switch_tile(tile) def draw_tile(self,gameDisplay): #####draw tiles in particular positioned for i in range(self.tiles_no): x,y = self.tilepos[self.tiles[i]] gameDisplay.blit(self.tile_images[i],(x,y)) def events(self, event): if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: #press space to random the tiles for i in range(100): self.set_tile_randomly()
- tiles_no stores no of tiles.
- Function set_Blank_pos() will get and set the blank position.
- Switch_tile function will switch the tles.
- close_to() function will return the adjacent tiles position to blank position that means will tiles can move in blank pos.
- events() functon take events.
- If space key pressed then set_tile_randomly() functin will calll in which the tiles will set randomly.
- update_tile_pos() function will update the tiles position when it clicked
4. Creating functions to draw fonts
def makeText(text, color, bgcolor, top, left): textSurf = font.render(text, True, color, bgcolor) textRect = textSurf.get_rect() textRect.topleft = (top, left) return (textSurf, textRect) # Generic method to draw fonts on the screen font_name = pygame.font.match_font('comic.ttf') def draw_text(display, text, size, x, y): font = pygame.font.Font(font_name, size) text_surface = font.render(text, True, brown) text_rect = text_surface.get_rect() text_rect.midtop = (x, y) gameDisplay.blit(text_surface, text_rect)
- makeText and draw_text is a function that helps to draw text on the screen in a given font and size.
- get_rect() is a method that will return a rect object
- x, y is the dimension of x and y-direction
- blit() is used to draw an image or text to the screen at a given position
5. Front screen of the game
def game_front_screen(): gameDisplay.blit(background, (0,0)) draw_text(gameDisplay, "SLIDING TILE GAME!", 90, WIDTH / 2, HEIGHT / 4) draw_text(gameDisplay, "Press a key to begin!", 80, WIDTH / 2, HEIGHT * 3 / 4) pygame.display.flip() waiting = True while waiting: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if event.type == pygame.KEYUP: waiting = False
- game_front_screen() function show the front game screen of game
- pygame.display.flip() will update only a portion of screen but if no argument will pass then it will update entire screen
- pygame.event.get() will return all the event stored in the pygame event queue
- If the type of the event is equal to quit then the pygame will quit
- event.KEYUP is the event that occurs when a keyboard key is pressed and released
6. Creating and defining levels
def level_screen(): L1, L1_RECT = makeText('Level1', RED,True,100 , 40) L2, L2_RECT = makeText('Level2', RED, True,500 , 40) L3, L3_RECT = makeText('Level3', RED, True,100 , 180) L4, L4_RECT = makeText('Level4', RED,True,500 , 180) L5, L5_RECT = makeText('Level5',RED, True, 100 , 320) L6, L6_RECT = makeText('Level6', RED,True,500 , 320) L7, L7_RECT = makeText('Level7', RED,True,100 , 460) L8, L8_RECT = makeText('Level8', RED,True,500 , 460 gameDisplay.blit(L1, L1_RECT) gameDisplay.blit(L2, L2_RECT) gameDisplay.blit(L3, L3_RECT) gameDisplay.blit(L4, L4_RECT) gameDisplay.blit(L5, L5_RECT) gameDisplay.blit(L6, L6_RECT) gameDisplay.blit(L7, L7_RECT) gameDisplay.blit(L8, L8_RECT) mpos = pygame.mouse.get_pos() for event in pygame.event.get(): if L1_RECT.collidepoint(mpos): level1() elif L2_RECT.collidepoint(mpos): level2() elif L3_RECT.collidepoint(mpos): level3() elif L4_RECT.collidepoint(mpos): level4() elif L5_RECT.collidepoint(mpos): level5() elif L6_RECT.collidepoint(mpos): level6() elif L7_RECT.collidepoint(mpos): level7() elif L8_RECT.collidepoint(mpos): level8() def level1(): program=Generate_Puzzle((3,3),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level2(): program=Generate_Puzzle((3,4),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level3(): program=Generate_Puzzle((4,3),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level4(): program=Generate_Puzzle((4,4),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level5(): program=Generate_Puzzle((4,5),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level6(): program=Generate_Puzzle((5,5),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level7(): program=Generate_Puzzle((5,4),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt) def level8(): program=Generate_Puzzle((6,5),80,5) while True: dt = clock.tick()/1000 gameDisplay.blit(background, (0,0)) draw_text(gameDisplay,'PRESS SPACE TO START GAME', 60,370 , 500) program.draw_tile(gameDisplay) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit();sys.exit() program.events(event) program.update_tile_pos(dt)
level_screen() function will display levels on game window and checking the collision of the level postion and mouse postion . according to the coliision it will call the level. We create 8 levels in our game. Each level has their different grid value.
7. Main loop of the game
game_over = True game_running = True while game_running : if game_over : game_front_screen() game_over = False for event in pygame.event.get(): if event.type == pygame.QUIT: game_running = False gameDisplay.blit(background, (0,0)) level_screen() pygame.display.update() clock.tick(FPS) pygame.quit()
- This is the mainloop of the game
- If game_over is true then call game_front_screen() function
- game_running used to manage the while loop. If game_running become false then terminates the game While loop
- Event type quit will close the game window
- clock.tick() will keep the loop running at the right speed (manages the frame/second).
Project output
Summary
In this sliding tile puzzle python project, we used popular pygame library which is used to build game and multimedia application. We create multiple levels in the game. We also used random module to randomly organize tiles when space key will pressed. In this way, we successfully developed the sliding tile game of multiple levels in Python.