vlatkovski

Sliding puzzle game in Processing

Nov 8th, 2021 (edited)
996
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.13 KB | None | 0 0
  1. import os
  2. from random import shuffle
  3.  
  4.  
  5. class Tile:
  6.     def __init__(self, id, corner, side_length, images_path, empty = False):
  7.         print(id, corner, side_length, images_path)
  8.         print(os.path.join(images_path, str(id) + ".png"))
  9.         self.id = id
  10.         self.corner = corner
  11.         self.side_length = side_length
  12.         self.img = loadImage(os.path.join(images_path, str(id) + ".png"))
  13.         self.empty = empty
  14.    
  15.     def swap_position(self, other):
  16.         self.corner, other.corner = other.corner, self.corner
  17.    
  18.     def draw(self, draw_corners=True, draw_if_empty=False):
  19.         if self.empty and not draw_if_empty:
  20.             fill(0)
  21.             rect(self.corner[0], self.corner[1], self.side_length, self.side_length)
  22.         else:
  23.             image(
  24.                 self.img,
  25.                 self.corner[0],
  26.                 self.corner[1],
  27.                 self.side_length,
  28.                 self.side_length
  29.             )
  30.        
  31.         if not draw_corners:
  32.             return
  33.  
  34.         corners = [[None for _ in range(2)] for _ in range(2)]
  35.         for i in range(2):
  36.             for j in range(2):
  37.                 corners[i][j] = (
  38.                     self.corner[0] + (self.side_length if i else 0),
  39.                     self.corner[1] + (self.side_length if j else 0)
  40.                 )
  41.                
  42.         line(corners[0][0][0], corners[0][0][1], corners[0][1][0], corners[0][1][1])
  43.         line(corners[0][0][0], corners[0][0][1], corners[1][0][0], corners[1][0][1])
  44.         line(corners[0][1][0], corners[0][1][1], corners[1][1][0], corners[1][1][1])
  45.         line(corners[1][0][0], corners[1][0][1], corners[1][1][0], corners[1][1][1])
  46.  
  47.     def __str__(self):
  48.         return "<Tile {} {} {} {} {}>".format(self.id, self.corner, self.side_length, self.img, self.empty)
  49.  
  50.     def __repr__(self):
  51.         return self.__str__()
  52.  
  53.  
  54. class Board:
  55.     def __init__(self, num_tiles, side_length, corner, images_path, shuffle_tiles = True):
  56.         self.num_tiles = num_tiles
  57.         self.corner = corner
  58.         self.side_length = side_length
  59.         self.dimension = int(sqrt(num_tiles))
  60.        
  61.         self.tiles = []
  62.         tile_side_length = floor(self.side_length / self.dimension)
  63.         tile_corner = self.corner
  64.  
  65.         tiles_order = [i for i in range(num_tiles-1)]
  66.         if shuffle_tiles:
  67.             shuffle(tiles_order)
  68.        
  69.         # add the last element, which is empty
  70.         tiles_order.append(num_tiles-1)
  71.        
  72.         for i in range(num_tiles):
  73.             if i % self.dimension == 0 and i > 0:
  74.                 tile_corner = (self.corner[0], tile_corner[1] + tile_side_length)
  75.    
  76.             id = tiles_order[i]
  77.             self.tiles.append(Tile(id, tile_corner, tile_side_length, images_path, id == num_tiles-1))
  78.             tile_corner = (tile_corner[0] + tile_side_length, tile_corner[1])
  79.    
  80.     def get_tile_num_from_point(self, p):
  81.         for i in range(self.num_tiles):
  82.             tile = self.tiles[i]
  83.             if tile.corner[0] <= p[0] < tile.corner[0] + tile.side_length:
  84.                 if tile.corner[1] <= p[1] < tile.corner[1] + tile.side_length:
  85.                     return i
  86.        
  87.         return -1
  88.    
  89.     def move_tile(self, id, change):
  90.         """Move the tile in a direction."""
  91.         num = None
  92.         for i in range(self.num_tiles):
  93.             if self.tiles[i].id == id:
  94.                 num = i
  95.                 break
  96.  
  97.         cell = (num // self.dimension, num % self.dimension)
  98.         other_cell = (cell[0] + change[0], cell[1] + change[1])
  99.         if not (0 <= other_cell[0] < self.dimension and 0 <= other_cell[1] < self.dimension):
  100.             return
  101.    
  102.         other_num = other_cell[0]*self.dimension + other_cell[1]
  103.            
  104.         # print("Moving num={} cell={} tile={} onum={} ocell={} otile={}".format(num, cell, self.tiles[num], other_num, other_cell, self.tiles[other_num]))
  105.                
  106.         self.tiles[num].swap_position(self.tiles[other_num])
  107.         self.tiles[num], self.tiles[other_num] = self.tiles[other_num], self.tiles[num]
  108.         self.tiles[num].draw()
  109.         self.tiles[other_num].draw()
  110.        
  111.     def move_tile_toward_empty(self, num):
  112.         """Move a non-empty tile by swapping it with the empty tile, only if they are adjacent."""
  113.         if self.tiles[num].id == self.num_tiles - 1:
  114.             return
  115.    
  116.         cell = (num // self.dimension, num % self.dimension)
  117.         # print("Will try to move toward empty num={}, cell={}, tile={}".format(num, cell, self.tiles[num]))
  118.    
  119.         for i in range(self.num_tiles):
  120.             if self.tiles[i].empty:
  121.                 empty_cell = (i // self.dimension, i % self.dimension)
  122.                 change = (cell[0] - empty_cell[0], cell[1] - empty_cell[1])
  123.                 if abs(change[0]) + abs(change[1]) == 1:
  124.                     # they are vertically or horizontally adjacent
  125.                     self.move_tile(self.num_tiles - 1, change)
  126.                     return True
  127.                
  128.                 return False
  129.         return False
  130.    
  131.     def draw_all_tiles(self, draw_corners=True, draw_empty=False):
  132.         for tile in self.tiles:
  133.             tile.draw(draw_corners, draw_empty)
  134.  
  135.  
  136. class Game:
  137.     def __init__(self, num_tiles, board_length, corner_point, images_path):
  138.         if int(sqrt(num_tiles))**2 != num_tiles:
  139.             raise ValueError()
  140.        
  141.         self.num_tiles = num_tiles
  142.         self.status = 1
  143.         self.board = Board(num_tiles, board_length, corner_point, images_path)
  144.         self.board.draw_all_tiles()
  145.                
  146.     def get_status(self):
  147.         return self.status
  148.      
  149.     def process_click(self, x, y):
  150.         num = self.board.get_tile_num_from_point((x, y))
  151.         # print("Processing click, x={} y={} num={}".format(x, y, num))
  152.         if 0 <= self.board.tiles[num].id < self.num_tiles - 1:
  153.             self.board.move_tile_toward_empty(num)
  154.             self.check_victory()
  155.            
  156.     def process_key(self, key_code):
  157.         directions = {}
  158.         directions[UP] = (1, 0)
  159.         directions[DOWN] = (-1, 0)
  160.         directions[LEFT] = (0, 1)
  161.         directions[RIGHT] = (0, -1)
  162.         if key_code in directions:
  163.             self.board.move_tile(self.num_tiles - 1, directions[key_code])
  164.             self.check_victory()
  165.  
  166.     def check_victory(self):
  167.         if self.status != 1:
  168.             return
  169.        
  170.         # status is 1 (game ongoing)
  171.         for i in range(self.num_tiles):
  172.             if self.board.tiles[i].id != i:
  173.                 return
  174.            
  175.         # success, all are good
  176.         self.status = 2
  177.         self.board.draw_all_tiles(False, True)
  178.         print("The game has ended!")
  179.  
  180.  
  181. g = None
  182. IMG_FOLDER_PATH = "img2"
  183.  
  184.  
  185. def setup():
  186.     size(600, 600)
  187.     background(0, 0, 0)
  188.     stroke(255, 255, 255)
  189.        
  190.     global g
  191.     g = Game(4, min(width, height), (0, 0), IMG_FOLDER_PATH)
  192.  
  193.  
  194. def draw():
  195.     pass
  196.  
  197.  
  198. def mouseClicked():
  199.     if g.get_status() != 1:
  200.         return
  201.    
  202.     g.process_click(mouseX, mouseY)
  203.  
  204.  
  205. def keyPressed():
  206.     if g.get_status() != 1:
  207.         return
  208.    
  209.     g.process_key(keyCode)
Add Comment
Please, Sign In to add comment