/ solver.py
solver.py
  1  import copy
  2  
  3  import visualizer
  4  import time
  5  
  6  
  7  class Board:
  8      SIZE = 56
  9  
 10      def __init__(self):
 11          self.grid = [[True for _ in range(Board.SIZE)] for _ in range(Board.SIZE)]  # grid[y][x] = True if unoccupied
 12          self.next_free = (0, 0)  # (x, y), the top leftmost free cell
 13          self.space = Board.SIZE * Board.SIZE  # free space on this board
 14  
 15  
 16      ''' Returns True if this piece fits at the top leftmost free space '''
 17      def does_fit(self, piece):
 18          # Ensure this piece fits within the bounds of the board
 19          if self.next_free[0] + piece[0] > Board.SIZE or self.next_free[1] + piece[1] > Board.SIZE:
 20              return False
 21  
 22          # Ensure each cell is free
 23          for w in range(piece[0]):
 24              for h in range(piece[1]):
 25                  if not self.grid[self.next_free[1] + h][self.next_free[0] + w]:
 26                      return False
 27  
 28          return True
 29  
 30  
 31      ''' Inserts this piece at the top leftmost free position
 32          Assumes this piece fits 
 33          Returns the top left of this inserted piece '''
 34      def insert(self, piece):
 35          position = copy.copy(self.next_free)
 36  
 37          # Fill in the cells occupied by this piece
 38          for x in range(piece[0]):
 39              for y in range(piece[1]):
 40                  self.grid[self.next_free[1] + y][self.next_free[0] + x] = False
 41  
 42          # Update top-leftmost free position
 43          updated = False
 44          for y in range(Board.SIZE):
 45              for x in range(Board.SIZE):
 46                  if not updated and self.grid[y][x]:
 47                      self.next_free = (x, y)
 48                      updated = True
 49  
 50  
 51          # Update remaining space
 52          self.space -= piece[0] * piece[1]
 53  
 54          return position
 55  
 56  
 57      ''' Return a copy of this board '''
 58      def copy(self):
 59          copied_board = Board()
 60          copied_board.grid = copy.deepcopy(self.grid)
 61          copied_board.next_free = copy.copy(self.next_free)
 62          copied_board.space = self.space
 63          return copied_board
 64  
 65  
 66  
 67  def get_solution(board, remaining, positions):
 68      visualizer.visualize(positions)
 69  
 70      if board.space == 0:
 71          return positions
 72  
 73      for piece in remaining:
 74          for isRotated in (False, True):
 75              rotated_piece = piece if not isRotated else (piece[1], piece[0])
 76              if board.does_fit(rotated_piece):
 77                  # insert piece into board, remove piece from remaining, append position
 78                  new_board = board.copy()
 79                  new_remaining = copy.deepcopy(remaining)
 80                  position = new_board.insert(rotated_piece)
 81                  new_remaining.remove(piece)
 82                  positions.append((rotated_piece, position))
 83  
 84                  # Get recursive solution
 85                  solution = get_solution(new_board, new_remaining, positions)
 86                  if solution:
 87                      return solution
 88  
 89                  # Revert unsuccessful position addition
 90                  positions.pop()
 91  
 92  
 93  
 94  ''' ======================= Run the Code ======================= '''
 95  visualizer = visualizer.Visualizer()
 96  
 97  all_pieces = [(28, 14), (21, 18), (21, 18), (21, 14), (21, 14), (32, 11), (32, 10), (28, 7), (28, 6), (17, 14), (14, 4), (10, 7)]
 98  board = Board()
 99  print(get_solution(board, all_pieces, []))
100  
101  time.sleep(25)