def move_tile_on_grid(self, tile: Tile, coordinates: Coordinates): if self.tiles_from_index.get(tile.get_id()) is None: raise TileNotExistsException("tile: (" + str(tile) + ") was not added") tile_on_coordinates = self.get_tile_from_grid(coordinates) if tile_on_coordinates is not None: if tile_on_coordinates.id != tile.id: raise TileTakenException( tile_on_coordinates, f"there is already tile: ({str(tile)}) on {str(coordinates)}" ) # else it means we move to same tile we were on previous_coordinates = self.coordinates_from_index.get(tile.get_id()) if previous_coordinates is None: raise TileNotExistsException("tile: (" + str(tile) + ") did not have coordinates") self.coordinates_from_index[tile.get_id()] = coordinates.copy() self.tile_grid[ previous_coordinates.get_array_index()] = BaseGrid.empty_tile_id self.tile_grid[coordinates.get_array_index()] = tile.get_id() self.tiles_from_index[tile.get_id()] = tile if tile.get_type() == TileType.BLOCK: self.block_tile_grid[ previous_coordinates.get_array_index()] = False self.block_tile_grid[coordinates.get_array_index()] = True
class RobotExecutorMockRotate(RobotExecutor): robot1_coordinates = Coordinates(2, 3) robot1_future_rotate = Direction.LEFT robot1_sleep = 1 robot2_coordinates = Coordinates(1, 3) robot2_future_rotate = Direction.DOWN robot2_sleep = 3 def __init__(self, where_rotate: Direction, how_long_sleep: int, robot: Robot, shared_grid_access: SharedGridAccess, goal_building: GoalBuilding): super().__init__(robot, shared_grid_access, goal_building) self.how_long_sleep = how_long_sleep self.where_rotate = where_rotate def start_process(self): sleep(self.how_long_sleep * 0.01) self.shared_actions_executor.try_rotate_robot(self.where_rotate) with self.shared_grid_access.grid_lock_sync as grid: if self.how_long_sleep == RobotExecutorMockRotate.robot1_sleep: robot1 = grid.get_tile_from_grid( RobotExecutorMockRotate.robot1_coordinates) assert robot1.rotation == RobotExecutorMockRotate.robot1_future_rotate if self.how_long_sleep == RobotExecutorMockRotate.robot2_sleep: robot1 = grid.get_tile_from_grid( RobotExecutorMockRotate.robot1_coordinates) assert robot1.rotation == RobotExecutorMockRotate.robot1_future_rotate robot2 = grid.get_tile_from_grid( RobotExecutorMockRotate.robot2_coordinates) assert robot2.rotation == RobotExecutorMockRotate.robot2_future_rotate
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 setUp(self): self.example_width = 5 self.example_height = 5 self.base_grid_example = BaseGrid(width=self.example_width, height=self.example_height) print("setup") self.block_tile = Tile(TileType.BLOCK) self.obstacle_tile = Tile(TileType.OBSTACLE) self.block_tile_coordinates = Coordinates(1, 1) self.obstacle_tile_coordinates = Coordinates(3, 3)
def pop_tile_from_grid(self, coordinates: Coordinates) -> Union[Tile, None]: tile_index = self.tile_grid[coordinates.get_array_index()] if tile_index is None: return None self.coordinates_from_index.pop(tile_index) self.tile_grid[coordinates.get_array_index()] = BaseGrid.empty_tile_id tile = self._get_tile_from_index(tile_index) if tile.get_type() == TileType.BLOCK: self.block_tile_grid[coordinates.get_array_index()] = False return tile
def create_simulation(parent, controller): robots: List[Robot] = list() how_many_robots = controller.number_of_robots robots_pos: List[Coordinates] = list() id = 10000 for pos in robots_pos_set: id += 1 robot = Robot(Direction.UP) robot.id = id robots.append(robot) robots_pos.append(pos) base_grid = BaseGrid(goal_building.width, goal_building.height) base_grid.add_tile_to_grid(Tile(TileType.SOURCE), Coordinates(0, 0)) base_grid.add_tile_to_grid(Tile(TileType.SOURCE), Coordinates(goal_building.width - 1, 0)) base_grid.add_tile_to_grid( Tile(TileType.SOURCE), Coordinates(goal_building.width - 1, goal_building.height - 1)) base_grid.add_tile_to_grid( Tile(TileType.SOURCE), Coordinates(0, goal_building.height - 1)) shared_grid_access = SharedGridAccess(base_grid, manager=Manager()) spin = Spin.ANTI_CLOCKWISE goal_to_edges_splitter = GoalToEdgesXSplitter(goal_building, spin) robot_executors: List[RobotExecutor] = list() for i in range(how_many_robots): robot_executors.append( SpiralRobotExecutor( robot=robots[i], shared_grid_access=shared_grid_access, goal_building=goal_building, goal_to_edges_splitter=goal_to_edges_splitter, spin=spin, start_offset=i, robot_coordinates=robots_pos[i], sleep_tick_seconds=0)) with shared_grid_access.grid_lock_sync as grid: for i in range(how_many_robots): grid.add_tile_to_grid(robots[i], robots_pos[i]) controller.robot_executors = robot_executors controller.shared_grid_access = shared_grid_access controller.goal_building = goal_building for robot_executor in controller.robot_executors: robot_executor.start_working() controller.show_frame(GridWindow(parent, controller))
def change_tile_type(col, row): if grid_window[col][row].cget('bg') == 'grey76': grid_window[col][row].configure(bg='yellow') controller.number_of_robots += 1 robots_pos_set.add(Coordinates(col, row)) elif grid_window[col][row].cget('bg') == 'yellow': grid_window[col][row].configure(bg='grey76') controller.number_of_robots -= 1 robots_pos_set.remove(Coordinates(col, row)) if controller.number_of_robots == 0: button.configure(state='disabled') else: button.configure(state='normal')
def __init__(self, goal_building: GoalBuilding, robot_coordinates: Coordinates): super().__init__(goal_building) width = self.goal_building.width height = self.goal_building.height self.source_positions = list() self.source_positions.append(SourcePosition(Coordinates(0, 0))) self.source_positions.append(SourcePosition(Coordinates(0, height - 1))) self.source_positions.append( SourcePosition(Coordinates(width - 1, height - 1))) self.source_positions.append(SourcePosition(Coordinates(width - 1, 0))) self.robot_coordinates = robot_coordinates self.is_splitted = False
def go_to_goal(self, goal: Coordinates): goal = goal.copy() while not self._is_robot_on_same_edge_and_not_too_far(goal): robot_edge_side = self.robot_coordinates.get_edge_side( width=self.width, height=self.height) next_corner = self.spin.get_edge_next_corner(robot_edge_side, width=self.width, height=self.height) pre_corner_pos = self.spin.get_pre_corner_coordinates(next_corner) moving_direction = self.spin.get_edge_move_direction( robot_edge_side) if self.robot_coordinates != pre_corner_pos: self.shared_actions_executor.try_rotate_robot(moving_direction) while self.robot_coordinates != pre_corner_pos: hit_information = self.shared_actions_executor.try_move_robot( moving_direction) if hit_information.hit_type != HitType.NO_HIT: self.shared_actions_executor.wait_action() # robot is on pre_corner_coordinates self._go_around_corner(moving_direction) # here robot is on same edge as goal moving_direction = self.robot_coordinates.get_to_other_direction(goal) if self.robot.rotation != moving_direction: self.shared_actions_executor.try_rotate_robot(moving_direction) while self.robot_coordinates != goal: hit_information = self.shared_actions_executor.try_move_robot( moving_direction) if hit_information.hit_type != HitType.NO_HIT: self.shared_actions_executor.wait_action()
def test_put_block(self): base_grid = BaseGrid(5, 5) robot = Robot(Direction.UP) robot_coordinates = Coordinates(4, 4) inner_block = Tile(TileType.BLOCK) robot.take_block(inner_block) base_grid.add_tile_to_grid(robot, robot_coordinates) shared_grid_access = SharedGridAccess(base_grid, Manager()) h_info = shared_grid_access.try_put_block(robot, Direction.UP) assert h_info.hit_type == HitType.ERROR assert isinstance(h_info.inner_error, OutOfBoundCoordinatesError) h_info = shared_grid_access.try_put_block(robot, Direction.LEFT) assert h_info.hit_type == HitType.ERROR assert isinstance(h_info.inner_error, WrongBlockPutDirection) h_info = shared_grid_access.try_rotate_robot(robot, Direction.LEFT) assert h_info.hit_type == HitType.ROTATED robot.rotate_to_direction(Direction.LEFT) h_info = shared_grid_access.try_put_block(robot, Direction.LEFT) assert h_info.hit_type == HitType.PLACED_BLOCK inner_block = robot.pop_block() h_info = shared_grid_access.try_move_robot(robot, Direction.LEFT) assert h_info.hit_type == HitType.BLOCK assert isinstance(h_info.inner_error, TileTakenException) assert inner_block == h_info.inner_error.get_tile()
def __init__(self, start_coordinates: Coordinates, direction: Direction, block_line: Iterable[bool]): self.block_line = copy.deepcopy(block_line) self.block_positions = LineToMiddle.get_block_positions_from_block_line( block_line) self.direction = direction self.start_coordinates = start_coordinates.copy() self.blocks_placed = 0 self.blocks_to_place = len(self.block_positions)
def add_tile_to_grid(self, tile: Tile, coordinates: Coordinates): if self.tiles_from_index.get(tile.get_id()) is None: self.add_new_tile(tile) else: tile_coordinates = self.coordinates_from_index.get(tile.get_id()) if tile_coordinates is not None: raise AddDuplicateTileError("tile " + str(tile) + " already exists on " + str(tile_coordinates)) tile_on_coordinates = self.get_tile_from_grid(coordinates) if tile_on_coordinates is not None: raise TileTakenException( tile_on_coordinates, f"there is already tile: ({str(tile)}) on {str(coordinates)}") self.tile_grid[coordinates.get_array_index()] = tile.get_id() self.coordinates_from_index[tile.get_id()] = coordinates if tile.get_type() == TileType.BLOCK: self.block_tile_grid[coordinates.get_array_index()] = True
class TestBaseGrid(TestCase): def setUp(self): self.example_width = 5 self.example_height = 5 self.base_grid_example = BaseGrid(width=self.example_width, height=self.example_height) print("setup") self.block_tile = Tile(TileType.BLOCK) self.obstacle_tile = Tile(TileType.OBSTACLE) self.block_tile_coordinates = Coordinates(1, 1) self.obstacle_tile_coordinates = Coordinates(3, 3) def test_add_new_tile_when_it_exists(self): self.base_grid_example.add_new_tile(self.block_tile) with self.assertRaises(TileAlreadyAddedException): self.base_grid_example.add_new_tile(self.block_tile) def test_add_get_tile_from_grid(self): self.base_grid_example.add_new_tile(self.block_tile) self.base_grid_example.add_new_tile(self.obstacle_tile) self.base_grid_example.add_tile_to_grid( tile=self.block_tile, coordinates=self.block_tile_coordinates) tile_from_block_tile_coordinates = self.base_grid_example.get_tile_from_grid( coordinates=self.block_tile_coordinates) assert tile_from_block_tile_coordinates == self.block_tile with self.assertRaises(TileTakenException): self.base_grid_example.add_tile_to_grid( tile=self.obstacle_tile, coordinates=self.block_tile_coordinates) self.base_grid_example.add_tile_to_grid( tile=self.obstacle_tile, coordinates=self.obstacle_tile_coordinates) tile_from_obstacle_tile_coordinates = self.base_grid_example.get_tile_from_grid( coordinates=self.obstacle_tile_coordinates) assert tile_from_obstacle_tile_coordinates == self.obstacle_tile def test_copy(self): self.test_add_get_tile_from_grid() grid_copy = self.base_grid_example.copy() tile_from_block_tile_coordinates = grid_copy.get_tile_from_grid( coordinates=self.block_tile_coordinates) print("copied", tile_from_block_tile_coordinates) print("not copied", self.block_tile) assert tile_from_block_tile_coordinates == self.block_tile new_block_coordinates = self.block_tile_coordinates.create_neighbour_coordinate( Direction.UP) print("new block coordinate", new_block_coordinates) grid_copy.move_tile_on_grid(self.block_tile, new_block_coordinates) assert grid_copy.get_tile_from_grid( new_block_coordinates) == self.block_tile assert grid_copy.get_tile_from_grid( self.block_tile_coordinates) is None assert self.base_grid_example.get_tile_from_grid( new_block_coordinates) != self.block_tile assert self.base_grid_example.get_tile_from_grid( self.block_tile_coordinates) == self.block_tile
def test_another_robot_update_private_grid(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 1 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_1 = Robot(Direction.DOWN) robot_1.take_block(Tile(TileType.BLOCK)) robot_2 = Robot(Direction.UP) robot_2.take_block(Tile(TileType.BLOCK)) line_start_coordinates = Coordinates(0, 3) robot_1_coordinates = Coordinates(0, 4) robot_2_coordinates = Coordinates(0, 2) base_grid = BaseGrid(goal_building.width, goal_building.height) base_grid.add_tile_to_grid(robot_1, robot_1_coordinates) base_grid.add_tile_to_grid(robot_2, robot_2_coordinates) shared_grid_access = SharedGridAccess(base_grid, manager=Manager()) line_to_middle = LineToMiddle(start_coordinates=line_start_coordinates, direction=Direction.RIGHT, block_line=list( map(bool, [0, 0, 1, 0, 1]))) robot_1_executor = LineScannerWrapperExecutor( line=line_to_middle, robot=robot_1, shared_grid_access=shared_grid_access, goal_building=goal_building) robot_2_executor = LineScannerWrapperExecutor( line=line_to_middle, robot=robot_2, shared_grid_access=shared_grid_access, goal_building=goal_building) robot_1_executor.start_working() robot_2_executor.start_working() robot_1_executor.wait_for_finish() robot_2_executor.wait_for_finish() grid = shared_grid_access.get_private_copy() assert goal_building.validate_grid(grid)
def _is_robot_on_same_edge_and_not_too_far(self, goal: Coordinates) -> bool: robot_edge_side = self.robot_coordinates.get_edge_side( width=self.width, height=self.height) goal_edge_side = goal.get_edge_side(width=self.width, height=self.height) if robot_edge_side != goal_edge_side: return False moving_direction = self.spin.get_edge_move_direction(robot_edge_side) # distance <0 means we already are too far from source and need to make another lap return self.robot_coordinates.get_straight_distance_to_other( moving_direction, goal) >= 0
def test_shared_sync(self): base_grid = BaseGrid(5, 5) robot1 = Robot(Direction.RIGHT) robot1_coordinates = Coordinates(2, 2) robot2 = Robot(Direction.UP) robot2_coordinates = Coordinates(1, 3) base_grid.add_tile_to_grid(robot1, robot1_coordinates) base_grid.add_tile_to_grid(robot2, robot2_coordinates) shared_grid_access = SharedGridAccess(base_grid, Manager()) shared_grid_access.try_rotate_robot(robot1, Direction.LEFT) robot1.rotate_to_direction(Direction.LEFT) shared_grid_access.try_move_robot(robot2, Direction.UP) robot2_coordinates = robot2_coordinates.create_neighbour_coordinate(Direction.UP) with shared_grid_access.grid_lock_sync as grid: assert grid.get_tile_from_grid(robot1_coordinates) == robot1 assert grid.get_tile_from_grid(robot2_coordinates) == robot2 print(grid)
def get_tile_from_source(self, coordinates: Coordinates) -> Tile: try: tile_index = self.tile_grid[coordinates.get_array_index()] except IndexError as e: raise OutOfBoundCoordinatesError(e.args) tile = self._get_tile_from_index(tile_index) if tile is None: raise TileNotExistsException("tile index: (" + str(tile_index) + ") did not have tile") if tile.get_type() != TileType.SOURCE: raise TileNotSourceError(tile, "tile: (" + str(tile) + ") is not source") return Tile(TileType.BLOCK)
class RobotExecutorMockMove(RobotExecutor): robot1_coordinates = Coordinates(4, 4) robot1_move_direction = Direction.LEFT robot1_sleep = 1 robot2_coordinates = Coordinates(1, 3) robot2_move_direction = Direction.DOWN robot2_sleep = 3 def __init__(self, move_direction: Direction, how_long_sleep: int, robot: Robot, shared_grid_access: SharedGridAccess, goal_building: GoalBuilding): super().__init__(robot, shared_grid_access, goal_building) self.how_long_sleep = how_long_sleep self.move_direction = move_direction self.r1_c = RobotExecutorMockMove.robot1_coordinates.create_neighbour_coordinate( RobotExecutorMockMove.robot1_move_direction) self.r2_c = RobotExecutorMockMove.robot2_coordinates.create_neighbour_coordinate( RobotExecutorMockMove.robot2_move_direction) def start_process(self): sleep(self.how_long_sleep * 0.01) self.shared_actions_executor.try_move_robot(self.move_direction) with self.shared_grid_access.grid_lock_sync as grid: if self.how_long_sleep == RobotExecutorMockMove.robot1_sleep: robot1 = grid.get_tile_from_grid(self.r1_c) assert robot1 == self.robot if self.how_long_sleep == RobotExecutorMockMove.robot2_sleep: robot1 = grid.get_tile_from_grid(self.r1_c) assert robot1 is not None robot1 = grid.get_tile_from_grid( RobotExecutorMockMove.robot1_coordinates) assert robot1 is None robot2 = grid.get_tile_from_grid(self.r2_c) assert robot2 == self.robot robot2 = grid.get_tile_from_grid( RobotExecutorMockMove.robot2_coordinates) assert robot2 is None
def test_out_of_bound(self): base_grid = BaseGrid(5, 5) robot = Robot(Direction.UP) robot_coordinates = Coordinates(4, 4) base_grid.add_tile_to_grid(robot, robot_coordinates) shared_grid_access = SharedGridAccess(base_grid, Manager()) h_info = shared_grid_access.try_move_robot(robot, Direction.UP) assert h_info.hit_type == HitType.ERROR assert isinstance(h_info.inner_error, OutOfBoundCoordinatesError) with shared_grid_access.grid_lock_sync as grid: assert grid.get_tile_from_grid(robot_coordinates) == robot print(grid)
def __init__(self, start_coordinates: Coordinates, direction: Direction, block_line: Iterable[bool]): self.block_line = copy.deepcopy(block_line) self.block_positions = LineToMiddle.get_block_positions_from_block_line( block_line) self.direction = direction self.start_coordinates = start_coordinates.copy() self.blocks_placed = 0 self.blocks_to_place = len(self.block_positions) # last position where block could be placed or not if not self.is_finished(): self.last_position = self.start_coordinates.create_moved_coordinate( self.direction, self.block_positions[0]) else: self.last_position = self.start_coordinates
def __init__(self, diag_grid: np.ndarray, x_direction: Direction, y_direction: Direction, pos: Coordinates, width: int, height: int): self.height = height self.width = width self.pos: Coordinates = pos self.diag_grid = diag_grid self.x_direction = x_direction self.y_direction = y_direction self.last_x_pos = self.x_direction.is_x_or_y_rising() * (self.width - 1) self.last_y_pos = self.y_direction.is_x_or_y_rising() * (self.height - 1) self.last_pos = Coordinates(self.last_x_pos, self.last_y_pos) self.was_last_x = False self.was_last_y = False
def test_validate(self): base_grid = BaseGrid(5, 4) base_grid.add_tile_to_grid(Tile(TileType.BLOCK), Coordinates(1, 1)) base_grid.add_tile_to_grid(Tile(TileType.BLOCK), Coordinates(2, 2)) base_grid.add_tile_to_grid(Tile(TileType.BLOCK), Coordinates(3, 1)) base_grid.add_tile_to_grid(Tile(TileType.BLOCK), Coordinates(4, 0)) goal_building = GoalBuilding2D(self.text_grid) assert goal_building.validate_grid(base_grid) base_grid.add_tile_to_grid(Tile(TileType.BLOCK), Coordinates(3, 3)) assert not goal_building.validate_grid(base_grid) base_grid.pop_tile_from_grid(Coordinates(3, 3)) assert goal_building.validate_grid(base_grid) base_grid.remove_tile_from_grid(Coordinates(2, 2)) assert not goal_building.validate_grid(base_grid) print(str(goal_building))
def get_edge_next_corner(self, edge_side: Direction, width: int, height: int) -> Coordinates: max_x = width - 1 max_y = height - 1 if self == Spin.CLOCKWISE: if edge_side == Direction.UP: return Coordinates(max_x, max_y) elif edge_side == Direction.RIGHT: return Coordinates(max_x, 0) elif edge_side == Direction.DOWN: return Coordinates(0, 0) else: return Coordinates(0, max_y) if edge_side == Direction.UP: return Coordinates(0, max_y) elif edge_side == Direction.LEFT: return Coordinates(0, 0) elif edge_side == Direction.DOWN: return Coordinates(max_x, 0) else: return Coordinates(max_x, max_y)
def get_pre_corner_coordinates(self, corner: Coordinates) -> Coordinates: if self == Spin.ANTI_CLOCKWISE: if corner.x == 0: if corner.y == 0: return Coordinates(0, 1) # we assume y == height return Coordinates(1, corner.y) # we assume x == width elif corner.y != 0: # we assume y == height return Coordinates(corner.x, corner.y - 1) return Coordinates(corner.x - 1, 0) if corner.x == 0: if corner.y == 0: return Coordinates(1, 0) # we assume y == height return Coordinates(0, corner.y - 1) # we assume x == width elif corner.y != 0: # we assume y == height return Coordinates(corner.x - 1, corner.y) return Coordinates(corner.x, 1)
def get_position(self, direction: Direction) -> SourcePosition: max_x = self.width - 1 max_y = self.height - 1 if direction == Direction.LEFT: if self.spin == Spin.CLOCKWISE: return SourcePosition(Coordinates(0, 0)) else: return SourcePosition(Coordinates(0, max_y)) elif direction == Direction.UP: if self.spin == Spin.CLOCKWISE: return SourcePosition(Coordinates(0, max_y)) else: return SourcePosition(Coordinates(max_x, max_y)) elif direction == Direction.RIGHT: if self.spin == Spin.CLOCKWISE: return SourcePosition(Coordinates(max_x, max_y)) else: return SourcePosition(Coordinates(max_x, 0)) elif direction == Direction.DOWN: if self.spin == Spin.CLOCKWISE: return SourcePosition(Coordinates(max_x, 0)) else: return SourcePosition(Coordinates(0, 0))
def __init__(self, robot: Robot, shared_grid_access: SharedGridAccess, goal_building: GoalBuilding, goal_to_edges_splitter: GoalToEdgesSplitter, spin: Spin, sleep_tick_seconds: float = None, robot_coordinates: Coordinates = None, start_offset: int = 0, start_edge_index: int = None): super().__init__(robot, shared_grid_access, goal_building, robot_coordinates=robot_coordinates, sleep_tick_seconds=sleep_tick_seconds) self.private_grid.add_tile_to_grid(self.robot, self.robot_coordinates.copy()) self.start_offset = start_offset self.robot_coordinates = self.private_grid.get_coord_from_tile(robot) self.spin = spin self.highway_executor = HighwayExecutor( shared_actions_executor=self.shared_actions_executor, spin=spin ) self.line_scanner_executor = LineScannerExecutor( shared_actions_executor=self.shared_actions_executor ) self.edges: List[GridEdge] = goal_to_edges_splitter.get_edges() if start_edge_index is None: edge_side = robot_coordinates.get_edge_side(width=goal_building.width, height=goal_building.height) next_side = spin.get_edge_move_direction(edge_side) for i in range(0, 4): self.edge_index = i self.edge = self.edges[self.edge_index] if next_side == self.edge.edge_side: print(f"robot: {robot} got side {next_side}") break else: self.edge_index = start_edge_index self.edge = self.edges[self.edge_index % 4]
def test_move_far_scenario(self): base_grid = BaseGrid(5, 5) goal_building = GoalBuilding(""" 0 0 0 0 0 0 0 1 0 0 0 1 2 1 0 0 0 1 2 0 0 0 0 0 0 """) # rotate, move, end coordinates: # if move or rotate is None then don't do it robot_states = [(Direction.UP, None, Coordinates(0, 0)), (None, Direction.UP, Coordinates(0, 1)), (Direction.DOWN, Direction.UP, Coordinates(0, 2)), (Direction.RIGHT, Direction.RIGHT, Coordinates(1, 2)), (None, Direction.RIGHT, Coordinates(2, 2)), (None, Direction.LEFT, Coordinates(1, 2))] rotate_directions = [state[0] for state in robot_states] moving_directions = [state[1] for state in robot_states] robot_coordinates = [state[2] for state in robot_states] robot = Robot(rotate_directions[0]) base_grid.add_tile_to_grid(robot, robot_coordinates[0]) shared_grid_access = SharedGridAccess(base_grid, Manager()) for i in range(1, len(robot_states)): rotate = rotate_directions[i] move = moving_directions[i] robot_executor = RobotRotateMoveMockExecutor( rotate, move, robot, shared_grid_access, goal_building) robot_executor.start_working() robot_executor.wait_for_finish() if rotate is not None: robot.rotate_to_direction(rotate) grid_copy = shared_grid_access.get_private_copy() # robot from grid has wrong direction robot_grid = grid_copy.get_tile_from_grid(robot_coordinates[i]) assert robot_grid == robot
def _split_goal(self): if self.is_splitted: return self.edges: List[GridEdge] = list() width = self.goal_building.width height = self.goal_building.height # first add elements that are not on diagonals # test_array = np.zeros((width, height), dtype=int) edge_block_counts = np.zeros( 4, dtype=int) # how many blocks each edge have assigned raising_diag_grid = np.zeros((width, height), dtype=bool) # True if diag on field decreasing_diag_grid = np.zeros((width, height), dtype=bool) if width == 1 or height == 1: raise ValueError("goal_building should be at least 3x3") if (width % 2 == 1) and (height % 2 == 1): mid_block_x = width // 2 mid_block_y = height // 2 mid_block_pos = (mid_block_x, mid_block_y) decreasing_diag_grid[mid_block_pos] = True raising_diag_grid[mid_block_pos] = True # D 0 R # 0 RD 0 # R 0 D decreasing_diag_left_pos = Coordinates(mid_block_x - 1, mid_block_y + 1) decreasing_diag_grid[ decreasing_diag_left_pos.get_array_index()] = True decreasing_diag_right_pos = Coordinates(mid_block_x + 1, mid_block_y - 1) decreasing_diag_grid[ decreasing_diag_right_pos.get_array_index()] = True raising_diag_left_pos = Coordinates(mid_block_x - 1, mid_block_y - 1) raising_diag_grid[raising_diag_left_pos.get_array_index()] = True raising_diag_right_pos = Coordinates(mid_block_x + 1, mid_block_y + 1) raising_diag_grid[raising_diag_right_pos.get_array_index()] = True else: # D R # R D left_x = width // 2 - 1 if height % 2 == 0: down_y = height // 2 - 1 else: down_y = height // 2 decreasing_diag_left_pos = Coordinates(left_x, down_y + 1) decreasing_diag_grid[ decreasing_diag_left_pos.get_array_index()] = True decreasing_diag_right_pos = Coordinates(left_x + 1, down_y) decreasing_diag_grid[ decreasing_diag_right_pos.get_array_index()] = True raising_diag_left_pos = Coordinates(left_x, down_y) raising_diag_grid[raising_diag_left_pos.get_array_index()] = True raising_diag_right_pos = Coordinates(left_x + 1, down_y + 1) raising_diag_grid[raising_diag_right_pos.get_array_index()] = True top_right_corner_walker = ToCornerWalker(raising_diag_grid, x_direction=Direction.RIGHT, y_direction=Direction.UP, pos=raising_diag_right_pos, width=width, height=height) top_right_corner_walker.update_diag_to_corner() down_right_corner_walker = ToCornerWalker( decreasing_diag_grid, x_direction=Direction.RIGHT, y_direction=Direction.DOWN, pos=decreasing_diag_right_pos, width=width, height=height) down_right_corner_walker.update_diag_to_corner() down_left_corner_walker = ToCornerWalker(raising_diag_grid, x_direction=Direction.LEFT, y_direction=Direction.DOWN, pos=raising_diag_left_pos, width=width, height=height) down_left_corner_walker.update_diag_to_corner() top_left_corner_walker = ToCornerWalker(decreasing_diag_grid, x_direction=Direction.LEFT, y_direction=Direction.UP, pos=decreasing_diag_left_pos, width=width, height=height) top_left_corner_walker.update_diag_to_corner() both_diags = (raising_diag_grid + 2 * decreasing_diag_grid) # now we want to create lines for each edge: edge_builds: List[EdgeBuild] = [ EdgeBuild(width, height, direction.get_opposite()) for direction in Direction ] edge_num = -1 for direction in Direction: edge_num += 1 direction: Direction = direction if direction.is_x_axis(): # for x axis we have y axis length amount of lines edge_len = height opposite_len = width else: edge_len = width opposite_len = height # for each line for i in range(edge_len): # if direction = UP # we would have something like this: # if rising then last index if direction == Direction.LEFT: line_scan_coordinate = Coordinates(0, i) elif direction == Direction.UP: line_scan_coordinate = Coordinates(i, opposite_len - 1) elif direction == Direction.RIGHT: line_scan_coordinate = Coordinates(opposite_len - 1, i) else: # DOWN line_scan_coordinate = Coordinates(i, 0) edge_builds[edge_num].add_line_start(line_scan_coordinate) for j in range(opposite_len): diag_tile = both_diags[ line_scan_coordinate.get_array_index()] if diag_tile: if diag_tile != 10 and self.goal_building.grid[ line_scan_coordinate.get_array_index()]: both_diags[ line_scan_coordinate.get_array_index()] = 10 # TODO: decide where this tile goes # decide_later.append(block_line, coordinate, edge_set) something like this # for now lets just add to first that got this edge_builds[edge_num].block_lines[(i, j)] = True edge_block_counts[edge_num] += 1 break if self.goal_building.grid[ line_scan_coordinate.get_array_index()]: edge_builds[edge_num].block_lines[(i, j)] = True edge_block_counts[edge_num] += 1 line_scan_coordinate = line_scan_coordinate.create_neighbour_coordinate( direction.get_opposite()) edge_num = -1 for direction in Direction: edge_num += 1 edge_build = edge_builds[edge_num] lines: List[LineToMiddle] = list() for i in range(edge_build.length): line = LineToMiddle(edge_build.line_starts[i], direction.get_opposite(), edge_build.block_lines[i]) lines.append(line) edge = GridEdge(self.robot_coordinates, self.source_positions, edge_build.length, lines) self.edges.append(edge)
self._make_y_progress() else: self._make_x_progress() class GoalBuildingMock(GoalBuilding): def __init__(self): self.width = 11 self.height = 16 self.grid = np.zeros((self.width, self.height), dtype=bool) self.grid[(7, 3)] = True self.grid[(7, 4)] = True self.grid[(8, 3)] = True self.grid[(8, 4)] = True def validate_grid(self, base_grid: BaseGrid): pass if __name__ == '__main__': goal_building_mock = GoalBuildingMock() building = GoalBuilding2D(""" 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 """) splitter = GoalToEdgesXSplitter(building, Coordinates(1, 0)) splitter._split_goal()
def get_tile_from_grid(self, coordinates: Coordinates) -> Tile: try: tile_index = self.tile_grid[coordinates.get_array_index()] except IndexError as e: raise OutOfBoundCoordinatesError(e.args) return self._get_tile_from_index(tile_index)