philRG

Sokoban (starter)

Jul 2nd, 2021 (edited)
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.04 KB | None | 0 0
  1. import random
  2. import sys
  3. import math
  4. from typing import Tuple, List
  5.  
  6. DIRECTIONS = {'R': (1, 0), 'U': (0, -1), 'L': (-1, 0), 'D': (0, 1)}
  7.  
  8.  
  9. def idebug(*args):
  10.     # return
  11.     print(*args, file=sys.stderr, flush=True)
  12.  
  13.  
  14. def debug(*args):
  15.     # return
  16.     print(*args, file=sys.stderr, flush=True)
  17.  
  18.  
  19. class Cell(object):
  20.     """ :param pos: Position (x, y) de la cellule sur la grille
  21.        :param wall: est un mur ou pas
  22.        :type pos: bool
  23.        :type wall: bool
  24.        :return: class Cell
  25.        :rtype: object
  26.    """
  27.     pos: Tuple[int, int]
  28.     wall: bool
  29.     outside: bool
  30.     drop_zone: bool
  31.     neighbors: List[object]
  32.  
  33.     def __init__(self, x: int, y: int, c: str=None):
  34.         self.x, self.y = x, y
  35.         self.pos = (x, y)
  36.         self.wall: bool = c == '#'
  37.         self.outside: bool = True
  38.         # self.box: Box = None
  39.         self.drop_zone: bool = c == '*'
  40.         self.neighbors: List[Cell] = []
  41.  
  42.     # def clone(self):
  43.     #     cell = Cell(self.x, self.y)
  44.     #     cell.pos = self.pos
  45.     #     cell.wall = self.wall
  46.     #     cell.outside = self.outside
  47.     #     cell.drop_zone = self.drop_zone
  48.     #     cell.neighbors = [c.clone() for c in self.neighbors]
  49.     #     return cell
  50.  
  51.     def has_box(self, board):
  52.         for box in board.boxes:
  53.             if box.cell == self:
  54.                 return True
  55.  
  56.     def visit(self):
  57.         if not self.outside or self.wall:
  58.             return
  59.         self.outside = False
  60.         for cell in self.neighbors:
  61.             if cell is not None:
  62.                 cell.visit()
  63.  
  64.     def __repr__(self):
  65.         return f'{self.pos} {self.drop_zone}'
  66.  
  67.  
  68. class Pusher:
  69.     cell: Cell
  70.     moves: List[str]
  71.  
  72.     def __init__(self, cell: Cell):
  73.         self.cell = cell
  74.  
  75.     def clone(self):
  76.         pusher = Pusher(self.cell)
  77.         pusher.moves = self.moves[:]
  78.         return pusher
  79.  
  80.     def __repr__(self):
  81.         return f'{self.cell}'
  82.  
  83.  
  84. class Box:
  85.     cell: Cell
  86.  
  87.     def __init__(self, cell: Cell):
  88.         self.cell = cell
  89.  
  90.     def clone(self):
  91.         return Box(self.cell)
  92.  
  93.     def __repr__(self):
  94.         return f'{self.cell}'
  95.  
  96.  
  97. class Board:
  98.     grid: List[Cell]
  99.     pusher: Pusher
  100.     boxes: List[Box]
  101.  
  102.     def __init__(self, grid: List[Cell]=None):
  103.         self.grid: List[Cell] = grid
  104.         self.pusher: Pusher
  105.         self.boxes: List[Box] = []
  106.         if grid:
  107.             for cell in self.grid:
  108.                 for _dir in DIRECTIONS.values():
  109.                     new_pos = move(cell.pos, _dir)
  110.                     new_cell: Cell = self.get_cell(new_pos)
  111.                     if new_cell and not new_cell.wall:
  112.                         cell.neighbors.append(new_cell)
  113.         # self.walls = [c for c in self.grid if c.wall]
  114.  
  115.     def clone(self):
  116.         board: Board = Board()
  117.         board.grid = self.grid
  118.         board.pusher = self.pusher.clone()
  119.         board.boxes = [b.clone() for b in self.boxes]
  120.         return board
  121.  
  122.     def score(self):
  123.         return len([b for b in self.boxes if b.cell.drop_zone])
  124.  
  125.     def get_cell(self, pos: Tuple[int, int]):
  126.         tab = [c for c in self.grid if not c.wall and c.pos == pos]
  127.         return tab[0] if tab else None
  128.  
  129.     def get_box(self, pos: Tuple[int, int]):
  130.         tab = [b for b in self.boxes if b.cell.pos == pos]
  131.         return tab[0] if tab else None
  132.  
  133.     def is_box_pushable(self, cell: Cell):
  134.         exit_directions: List[str] = []
  135.         for d, _dir in DIRECTIONS.items():
  136.             new_pos = move(cell.pos, _dir)
  137.             new_cell = self.get_cell(new_pos)
  138.             if new_cell and not new_cell.wall:
  139.                 exit_directions.append(d)
  140.         if len(exit_directions) < 2:
  141.             return False
  142.         elif len(exit_directions) == 2:
  143.             if ''.join(set(exit_directions)) in ['LR', 'DU']:
  144.                 return True
  145.             else:
  146.                 return False
  147.         else:
  148.             return True
  149.  
  150.     def move_pusher(self, direction: str):
  151.         pos = move(self.pusher.cell.pos, DIRECTIONS[direction])
  152.         dest_cell = self.get_cell(pos)
  153.         self.pusher.cell = dest_cell
  154.         if dest_cell.has_box(self):
  155.             box = self.get_box(pos)
  156.             new_box_pos = move(dest_cell.pos, DIRECTIONS[direction])
  157.             box.cell = self.get_cell(new_box_pos)
  158.  
  159.     def update(self, boxes_pos: List[Tuple], pusher_pos: Tuple[int, int]):
  160.         self.pusher: Pusher = Pusher(self.get_cell(pusher_pos))
  161.         self.boxes: List[Box] = [Box(self.get_cell(pos)) for pos in boxes_pos]
  162.         self.pusher.moves: List[Tuple] = []
  163.         for d, _dir in DIRECTIONS.items():
  164.             pos = move(pusher_pos, _dir)
  165.             cell = self.get_cell(pos)
  166.             if cell and not cell.wall:
  167.                 if cell.has_box(self):
  168.                     new_pos = move(cell.pos, _dir)
  169.                     new_cell = self.get_cell(new_pos)
  170.                     if new_cell and not new_cell.wall and not new_cell.has_box(self) and self.is_box_pushable(new_cell):
  171.                         self.pusher.moves.append(d)
  172.                 else:
  173.                     self.pusher.moves.append(d)
  174.  
  175.     def __repr__(self):
  176.         return f'{self.grid} {self.pusher} {self.boxes}'
  177.  
  178.  
  179. # class GameState:
  180. #     def __init__(self, boxes: List[Box], pusher: Tuple[int, int]):
  181. #         self.boxes: List[Box] = boxes
  182. #         self.pusher: Tuple[int, int] = pusher
  183.  
  184.  
  185. walls = []
  186. floor = []
  187.  
  188. line = input()
  189. idebug(line)
  190. WIDTH, HEIGHT, BOX_COUNT = [int(i) for i in line.split()]
  191. grid = []
  192.  
  193. grid: List[Cell] = []
  194. for i in range(HEIGHT):
  195.     row = input()  # one line of the grid: space " " is floor, pound "#" is wall
  196.     idebug(row)
  197.     for j, c in enumerate(row):
  198.         grid.append(Cell(j, i, c))
  199. debug(f'grid: {grid}')
  200.  
  201. move = lambda a, b: (a[0] + b[0], a[1] + b[1])
  202.  
  203. """TODO: define a graph of actions/Gamestates for simulation (BFS, ...)?"""
  204. # graph = {}
  205. # for pos in floor:
  206. #     graph[pos] = []
  207. #     for move_dir in DIRS.values():
  208. #         new_pos = move(pos, move_dir)
  209. #         if new_pos not in walls:
  210. #             graph[pos].append(new_pos)
  211.  
  212. board: Board = Board(grid)
  213. # game loop
  214. while True:
  215.     line = input()
  216.     idebug(line)
  217.     pusher_x, pusher_y = [int(i) for i in line.split()]
  218.     boxes_pos = []
  219.     for i in range(BOX_COUNT):
  220.         line = input()
  221.         idebug(line)
  222.         box_x, box_y = [int(j) for j in line.split()]
  223.         boxes_pos.append((box_x, box_y))
  224.     board.update(boxes_pos=boxes_pos, pusher_pos=(pusher_x, pusher_y))
  225.  
  226.     # Write an action using print
  227.     # To debug: print("Debug messages...", file=sys.stderr, flush=True)
  228.     actions = board.pusher.moves
  229.     debug(actions)
  230.     scores = []
  231.     for move_dir in board.pusher.moves:
  232.         new_board: Board = board.clone()
  233.         new_board.move_pusher(move_dir)
  234.         scores.append((move_dir, new_board.score()))
  235.     best_score = max([score for move_dir, score in scores])
  236.     best_move = random.choice([move_dir for move_dir, score in scores if score == best_score])
  237.     # action = random.choice(actions)
  238.     print(best_move)
Add Comment
Please, Sign In to add comment