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
Example #2
0
    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()
Example #3
0
    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)
Example #4
0
    def test_small_rotate_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
            """)

        robot1 = Robot(Direction.DOWN)
        robot2 = Robot(Direction.RIGHT)

        base_grid.add_tile_to_grid(robot1,
                                   RobotExecutorMockRotate.robot1_coordinates)
        base_grid.add_tile_to_grid(robot2,
                                   RobotExecutorMockRotate.robot2_coordinates)

        shared_grid_access = SharedGridAccess(base_grid, Manager())

        robot1_executor = RobotExecutorMockRotate(
            where_rotate=RobotExecutorMockRotate.robot1_future_rotate,
            how_long_sleep=RobotExecutorMockRotate.robot1_sleep,
            robot=robot1,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building)

        robot2_executor = RobotExecutorMockRotate(
            where_rotate=RobotExecutorMockRotate.robot2_future_rotate,
            how_long_sleep=RobotExecutorMockRotate.robot2_sleep,
            robot=robot2,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building)

        robot1_executor.start_working()
        robot2_executor.start_working()

        robot1_executor.wait_for_finish()
        robot2_executor.wait_for_finish()

        with shared_grid_access.grid_lock_sync as grid:
            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
            print(grid)
Example #5
0
    def test_small_move_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
            """)

        robot1 = Robot(RobotExecutorMockMove.robot1_move_direction)
        robot2 = Robot(RobotExecutorMockMove.robot2_move_direction)

        base_grid.add_tile_to_grid(robot1,
                                   RobotExecutorMockMove.robot1_coordinates)
        base_grid.add_tile_to_grid(robot2,
                                   RobotExecutorMockMove.robot2_coordinates)

        shared_grid_access = SharedGridAccess(base_grid, Manager())

        robot1_executor = RobotExecutorMockMove(
            move_direction=RobotExecutorMockMove.robot1_move_direction,
            how_long_sleep=RobotExecutorMockMove.robot1_sleep,
            robot=robot1,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building)

        robot2_executor = RobotExecutorMockMove(
            move_direction=RobotExecutorMockMove.robot2_move_direction,
            how_long_sleep=RobotExecutorMockMove.robot2_sleep,
            robot=robot2,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building)

        robot1_executor.start_working()
        robot2_executor.start_working()

        robot1_executor.wait_for_finish()
        robot2_executor.wait_for_finish()

        with shared_grid_access.grid_lock_sync as grid:
            robot1_new = grid.get_tile_from_grid(robot2_executor.r1_c)
            assert robot1 == robot1_new
            robot2_new = grid.get_tile_from_grid(robot2_executor.r2_c)
            assert robot2 == robot2_new
            print(grid)
Example #6
0
        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 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)
Example #8
0
    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 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)
Example #10
0
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_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 test_multi_robot(self):
        text_grid = """
               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 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 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 1 0 0 0 0
               0 0 0 0 0 0 0 0 1 0 0 1 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 1 0 0 0 0 0 0 1 0 0 0 0
               0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 1 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0
               0 0 0 0 0 1 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 0 0 0 0 1 0 0
               0 0 0 0 0 1 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0
               0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0
               0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 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 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 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 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 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
               """
        goal_building = GoalBuilding2D(text_grid=text_grid)
        robots: List[Robot] = list()
        robots_pos: List[Coordinates] = list()
        how_many_robots = 4

        for i in range(how_many_robots):
            robots.append(Robot(Direction.UP))
            robots_pos.append(Coordinates(i+1, 0))

        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,
                start_edge_index=i % 4,
                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])

        for i in range(how_many_robots):
            robot_executors[i].start_working()

        for i in range(how_many_robots):
            robot_executors[i].wait_for_finish()

        grid = shared_grid_access.get_private_copy()
        assert goal_building.validate_grid(grid)
    def test_simple_map(self):
        text_grid = """
               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 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 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
               0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0
               0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
               0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 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
               0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
               """
        goal_building = GoalBuilding2D(text_grid=text_grid)
        robot_1 = Robot(Direction.DOWN)
        robot_1.id = 1000000001
        robot_2 = Robot(Direction.UP)
        robot_2.id = 1000000002
        robot_1_coordinates = Coordinates(0, 1)
        robot_2_coordinates = Coordinates(23, 16)

        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_1_executor = SpiralRobotExecutor(
            robot=robot_1,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building,
            goal_to_edges_splitter=goal_to_edges_splitter,
            spin=spin,
            start_offset=0,
            start_edge_index=0,
            robot_coordinates=robot_1_coordinates,
            sleep_tick_seconds=0.000001
        )

        robot_2_executor = SpiralRobotExecutor(
            robot=robot_2,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building,
            goal_to_edges_splitter=goal_to_edges_splitter,
            spin=spin,
            start_offset=0,
            start_edge_index=2,
            robot_coordinates=robot_2_coordinates,
            sleep_tick_seconds=0.000001
        )

        with shared_grid_access.grid_lock_sync as grid:
            grid.add_tile_to_grid(robot_1, robot_1_coordinates)
            grid.add_tile_to_grid(robot_2, robot_2_coordinates)

        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 test_robot_crash_updated_tiles_not_by_self_with_sleeps(self):
        text_grid = """
        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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
        """
        goal_building = GoalBuilding2D(text_grid=text_grid)
        robot_1 = Robot(Direction.DOWN)
        robot_1_source = Tile(TileType.SOURCE)
        robot_2 = Robot(Direction.UP)
        robot_2_source = Tile(TileType.SOURCE)
        line_start_coordinates = Coordinates(0, 9)
        base_grid = BaseGrid(goal_building.width, goal_building.height)
        robot_1_coordinates = Coordinates(0, 16)
        base_grid.add_tile_to_grid(robot_1, robot_1_coordinates)
        base_grid.add_tile_to_grid(
            robot_1_source,
            robot_1_coordinates.create_neighbour_coordinate(Direction.UP))
        robot_2_coordinates = Coordinates(0, 1)
        base_grid.add_tile_to_grid(robot_2, robot_2_coordinates)
        base_grid.add_tile_to_grid(
            robot_2_source,
            robot_2_coordinates.create_neighbour_coordinate(Direction.DOWN))

        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, map(int,
                              text_grid.split("\n")[9].split()))))
        robot_1_executor = LineScannerWithSourceWrapperExecutor(
            line=line_to_middle,
            robot=robot_1,
            shared_grid_access=shared_grid_access,
            goal_building=goal_building)
        robot_2_executor = LineScannerWithSourceWrapperExecutor(
            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)