def try_move_robot(self, robot: Robot,
                    direction: Direction) -> HitInformation:
     robot = robot.copy()
     with self.grid_lock_sync as grid:
         try:
             coordinates = SharedGridAccess._get_robot_coordinates(
                 grid, robot)
         except WrongTileError as e:
             return HitInformation(HitType.ERROR, e)
         try:
             robot.validate_movement_direction(direction)
         except ImpossibleRobotMovementError as e:
             return HitInformation(HitType.ERROR, e)
         new_coordinates = coordinates.create_neighbour_coordinate(
             direction)
         try:
             grid.move_tile_on_grid(robot, new_coordinates)
         except TileTakenException as e:
             tile = e.get_tile()
             return HitInformation(HitType.from_tile_type(tile.get_type()),
                                   e)
         except OutOfBoundCoordinatesError as e:
             return HitInformation(HitType.ERROR, e)
         # no need to update robot cause inner state is the same
         # print("robot: ", robot, "moved to ", new_coordinates)
         return HitInformation(HitType.NO_HIT, updated_robot=robot)
 def finish_robot(self, robot: Robot):
     robot = robot.copy()
     with self.grid_lock_sync as grid:
         try:
             coordinates = SharedGridAccess._get_robot_coordinates(
                 grid, robot)
         except WrongTileError as e:
             return HitInformation(HitType.ERROR, e)
         grid.remove_tile_from_grid(coordinates)
         return HitInformation(HitType.ROTATED, updated_robot=robot)
 def try_rotate_robot(self, robot: Robot, direction: Direction) -> HitInformation:
     # we need to make copy to not mess with input robot
     robot = robot.copy()
     with self.grid_lock_sync as grid:
         try:
             SharedGridAccess._validate_robot(grid, robot)
         except WrongTileError as e:
             return HitInformation(HitType.ERROR, e)
         robot.rotate_to_direction(direction)
         grid.update_tile(robot)
         return HitInformation(HitType.ROTATED, updated_robot=robot)
 def try_get_block(self, robot: Robot, direction: Direction):
     robot = robot.copy()
     with self.grid_lock_sync as grid:
         try:
             coordinates = SharedGridAccess._get_robot_coordinates(grid, robot)
             source_coordinates = coordinates.create_neighbour_coordinate(direction)
             robot.validate_get_block_direction(direction)
             block = grid.get_tile_from_source(source_coordinates)
             robot.take_block(block)
         except (OutOfBoundCoordinatesError, TileNotExistsException, TileNotSourceError,
                 WrongTileError, HasInnerBlockError, WrongBlockGetDirection) as e:
             return HitInformation(HitType.ERROR, e)
         grid.update_tile(robot)
         return HitInformation(HitType.GOT_BLOCK, updated_robot=robot)
 def try_put_block(self, robot: Robot, direction: Direction) -> HitInformation:
     # we need to make copy to not mess with input robot
     robot = robot.copy()
     with self.grid_lock_sync as grid:
         try:
             coordinates = SharedGridAccess._get_robot_coordinates(grid, robot)
             robot.validate_put_block_direction(direction)
             block_coordinates = coordinates.create_neighbour_coordinate(direction)
             grid.add_tile_to_grid(robot.pop_block(), block_coordinates)
         except (OutOfBoundCoordinatesError, WrongTileError, NoInnerBlockError, WrongBlockPutDirection) as e:
             return HitInformation(HitType.ERROR, e)
         except TileTakenException as e:
             tile = e.get_tile()
             return HitInformation(HitType.from_tile_type(tile.get_type()), e)
         grid.update_tile(robot)
         print("robot: ", robot, "placed to ", block_coordinates)
         return HitInformation(HitType.PLACED_BLOCK, updated_robot=robot)