def scan_line(self, line: LineToMiddle, _first_iteration: bool = True):
     # TODO: remove when work
     if _first_iteration:
         raise NotImplementedError()
     # end remove
     if line.is_finished():
         raise ValueError("cannot scan finished line")
     line_start_coordinates = line.start_coordinates.copy()
     if _first_iteration:
         if self.robot_coordinates != line_start_coordinates:
             raise ValueError("scanner assume that robot is at line start")
     if not self.robot.has_block():
         raise ValueError("scanner assume that robot has block")
     to_block_direction = line.get_to_block_direction()
     from_block_direction = line.get_from_block_direction()
     before_block_coordinates = line.get_next_block_position(
     ).create_neighbour_coordinate(from_block_direction)
     if _first_iteration:
         if self._move_to_block_towards_inside(to_block_direction,
                                               from_block_direction, line,
                                               before_block_coordinates):
             return
     else:
         if self.robot_coordinates.get_straight_distance_to_other(
                 to_block_direction, before_block_coordinates) > 0:
             if self._move_to_block_towards_inside(
                     to_block_direction, from_block_direction, line,
                     before_block_coordinates):
                 return
         else:
             self._move_to_block_from_inside(from_block_direction,
                                             before_block_coordinates)
     while True:
         # we need to rotate in case we were not
         if self.robot.rotation != to_block_direction:
             self.shared_actions_executor.try_rotate_robot(
                 to_block_direction)
         # if we are just before position to put block and correctly rotated
         hit_information = self.shared_actions_executor.try_put_block(
             to_block_direction)
         if hit_information.hit_type == HitType.PLACED_BLOCK:
             line.place_block()
             break
         elif hit_information.hit_type == HitType.BLOCK:
             # when another robot already put this block
             line.place_block()
             if line.is_finished():
                 break
             before_block_coordinates = line.get_next_block_position(). \
                 create_neighbour_coordinate(from_block_direction)
             self._move_to_block_from_inside(from_block_direction,
                                             before_block_coordinates)
             continue
         else:
             raise ValueError(
                 "different tile type cannot be on position where block will be added"
             )
     self._go_back_to_start_line(from_block_direction, line)
 def test_single_robot_finish_single_block_goal(self):
     goal_building = GoalBuilding2D("""
     0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 1 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0
     """)
     robot = Robot(Direction.UP)
     robot.take_block(Tile(TileType.BLOCK))
     line_start_coordinates = Coordinates(0, 3)
     base_grid = BaseGrid(goal_building.width, goal_building.height)
     base_grid.add_tile_to_grid(robot, line_start_coordinates)
     shared_grid_access = SharedGridAccess(base_grid, manager=Manager())
     shared_actions_executor = RobotSharedActionsExecutor(
         robot=robot,
         shared_grid_access=shared_grid_access,
         private_grid=shared_grid_access.get_private_copy(),
         robot_coordinates=line_start_coordinates.copy())
     line_scanner_executor = LineScannerExecutor(
         shared_actions_executor=shared_actions_executor)
     line_to_middle = LineToMiddle(
         start_coordinates=line_start_coordinates.copy(),
         direction=Direction.RIGHT,
         block_line=map(bool, [0, 0, 0, 0, 1]))
     line_scanner_executor.scan_line(line=line_to_middle)
     grid = shared_grid_access.get_private_copy()
     assert line_to_middle.is_finished()
     assert goal_building.validate_grid(grid)
     assert grid.get_coord_from_tile(robot) == line_start_coordinates
 def _move_to_block_towards_inside(self, to_block_direction: Direction,
                                   from_block_direction: Direction,
                                   line: LineToMiddle,
                                   before_block_coordinates: Coordinates):
     # returns True when finished but False when still need to add block
     while self.robot_coordinates != before_block_coordinates:
         hit_information = self.shared_actions_executor.try_move_robot(
             to_block_direction)
         if hit_information.hit_type == HitType.OBSTACLE:
             raise ValueError("scanner cannot work with obstacles")
         elif hit_information.hit_type == HitType.BLOCK:
             placed_block_position: Union[None, Coordinates] = None
             discovered_block_position = self.robot_coordinates.create_neighbour_coordinate(
                 to_block_direction)
             while placed_block_position != discovered_block_position:
                 placed_block_position = self._put_block_on_map(line)
             if line.is_finished():
                 self._go_back_to_start_line(from_block_direction,
                                             line.start_coordinates)
                 return
             self.shared_actions_executor.try_rotate_robot(
                 from_block_direction)
             before_block_coordinates = line.get_next_block_position(). \
                 create_neighbour_coordinate(from_block_direction)
             self._move_to_block_from_inside(from_block_direction,
                                             before_block_coordinates)
             return
         elif hit_information.hit_type == HitType.ROBOT:
             # if we hit robot then he already put at least one new block and we continue with block elsewhere
             self._put_block_on_map(line)
             self._go_back_to_start_line(from_block_direction,
                                         line.start_coordinates)
             return
     return
예제 #4
0
 def _move_to_block_towards_inside(self, line: LineToMiddle) -> bool:
     to_block_direction = line.get_to_block_direction()
     from_block_direction = line.get_from_block_direction()
     before_block_coordinates = line.get_next_block_position(
     ).create_neighbour_coordinate(from_block_direction)
     before_last_coordinates = line.get_last_position(
     ).create_neighbour_coordinate(from_block_direction)
     # print(f"robot: {self.robot}, start move_to_block_towards_inside, " +
     #       f"before: {before_block_coordinates}, last: {before_last_coordinates}")
     # returns True when finished but False when still need to add block
     while self.robot_coordinates != before_last_coordinates:
         hit_information = self.shared_actions_executor.try_move_robot(
             to_block_direction)
         if hit_information.hit_type == HitType.OBSTACLE:
             raise ValueError("scanner cannot work with obstacles")
         elif hit_information.hit_type == HitType.BLOCK:
             placed_block_position: Coordinates = before_block_coordinates
             discovered_block_position = self.robot_coordinates.create_neighbour_coordinate(
                 to_block_direction)
             print(
                 f"robot: {self.robot.id}, hit block at {discovered_block_position}"
             )
             if before_block_coordinates == discovered_block_position:
                 self._put_block_on_map(line)
             while placed_block_position != discovered_block_position:
                 placed_block_position = self._put_block_on_map(line)
             if line.is_finished():
                 self._go_back_to_start_line(from_block_direction,
                                             line.start_coordinates)
                 return True
             self.shared_actions_executor.try_rotate_robot(
                 from_block_direction)
             before_block_coordinates = line.get_next_block_position(). \
                 create_neighbour_coordinate(from_block_direction)
             self._move_to_block_from_inside(from_block_direction,
                                             before_block_coordinates)
             return False
         elif hit_information.hit_type == HitType.ROBOT:
             # if we hit robot then he already put at least one new block and we continue with block elsewhere
             other_robot_position = self.robot_coordinates.create_neighbour_coordinate(
                 to_block_direction)
             print(
                 f"robot: {self.robot.id}, hit robot at {other_robot_position}"
             )
             self._go_back_to_start_line(from_block_direction,
                                         line.start_coordinates)
             return True
     self.shared_actions_executor.try_rotate_robot(from_block_direction)
     before_block_coordinates = line.get_next_block_position(). \
         create_neighbour_coordinate(from_block_direction)
     self._move_to_block_from_inside(from_block_direction,
                                     before_block_coordinates)
     return False
 def _go_back_to_start_line(self, from_block_direction: Direction,
                            line: LineToMiddle):
     line_start_position = line.start_coordinates.copy()
     if self.robot_coordinates == line_start_position:
         return
     if self.robot.rotation != from_block_direction:
         self.shared_actions_executor.try_rotate_robot(from_block_direction)
     met_robot = False
     hit_information = None
     while self.robot_coordinates != line_start_position:
         if not met_robot:
             hit_information = self.shared_actions_executor.try_move_robot(
                 from_block_direction)
             if hit_information.hit_type == HitType.OBSTACLE:
                 raise ValueError("scanner cannot work with obstacles")
             elif hit_information.hit_type == HitType.BLOCK:
                 # we wait for other robot to take this block back
                 self.shared_actions_executor.wait_action()
             elif hit_information.hit_type == HitType.ROBOT:
                 # if we hit robot then he will know we put block
                 met_robot = True
         else:
             distance_to_line_start = self.robot_coordinates.get_straight_distance_to_other(
                 from_block_direction, line_start_position)
             if line.is_finished() or distance_to_line_start < 3:
                 # don't take block if line finished make other robot take it back he will go back updating one block
                 # in his private grid
                 [
                     self.shared_actions_executor.wait_action()
                     for _ in range(3)
                 ]
                 met_robot = False
             else:
                 hit_information = self.shared_actions_executor.try_get_block(
                     from_block_direction)
             if hit_information.hit_type == HitType.GOT_BLOCK:
                 raise NotImplementedError()