class TestCommandLine(unittest.TestCase):
    def setUp(self):
        time_step = 0.05
        self.agents = [Agent(0, 0, time_step)]
        self.arena = Arena(10, 20)
        self.biased_grid = BiasedGrid(self.arena.get_dimensions())
        self.algorithm = AStar(self.arena, self.agents, self.biased_grid)
        self.cli = CommandLine(self.arena, self.agents)

    def test_help(self):
        command = 'help'
        retval = self.cli.parse_command(command)
        self.assertTrue(retval)

    def test_help_specific(self):
        command = 'help move_agent'
        retval = self.cli.parse_command(command)
        self.assertTrue(retval)

    def test_agent_move(self):
        command = 'move_agent 0 X 4'
        retval = self.cli.parse_command(command)
        self.assertTrue(retval)

    def test_blockage(self):
        command = 'blockage set 4 4'
        retval = self.cli.parse_command(command)
        self.assertTrue(retval)
        self.assertEqual(TileState.BLOCKED, self.arena.get_tile_state(4, 4))
Ejemplo n.º 2
0
    def __init__(self,
                 arena: Arena,
                 agents: list,
                 routing_manager: MultiAgentAlgorithm,
                 biased_grid: BiasedGrid,
                 timestep: float,
                 dpi_scaling: int = 40) -> None:
        """
        Create a new canvas for rendering the simulation. The base canvas is based on an Arena object,
        which controls the domain of the simulation
        :param: arena: the arena object
        :param: agents: list of agents
        :param: routing_manager: routing manager object
        :param: biased_grid: biased grid for routing only in certain directions
        :param: timestep: the animation timestep in seconds
        :param: dpi_scaling: the dpi scaling to use for one grid square
        :return:
        """
        # initialize pygame as a renderer
        pygame.init()
        pygame.font.init()

        # create the rendering canvas
        self.x_size, self.y_size = arena.get_dimensions()
        self.dpi = dpi_scaling
        self._display_x = self.x_size * self.dpi
        self._display_y = self.y_size * self.dpi
        self.screen = pygame.display.set_mode(
            (self._display_x, self._display_y))
        self.clock = pygame.time.Clock()

        self.arena = arena
        self.agents = agents
        self.routing_manager = routing_manager
        self.biased_grid = biased_grid
        self.agent_selected = None
        self._render_directions = True
        self._event_tiles = None

        # dict of color keys
        self.colors_dict = {
            'tile_free': (180, 180, 180),
            'tile_blocked': (0, 0, 0),
            'tile_reserved': (60, 60, 60),
            'tile_target': (200, 135, 135),
            'grid_lines': (255, 255, 255),
            'agent': COLORS,
            'agent_selected': (245, 100, 90),
            'agent_border': (0, 0, 0),
            'soft_bias': (225, 225, 225),
            'hard_bias': (200, 80, 80),
            'event_tile': (255, 255, 200)
        }
        self.total_elements = len(self.colors_dict)
class TestAStar(unittest.TestCase):
    def setUp(self):
        time_step = 0.005
        self.arena = Arena(10, 10)
        self.biased_grid = BiasedGrid(self.arena.get_dimensions())
        self.agents = [Agent(0, 0, time_step), Agent(1, 1, time_step)]
        self.a_star = AStar(self.arena, self.agents, self.biased_grid)

    def test_a_star_init(self):
        self.assertEqual(self.arena, self.a_star.arena)
        self.assertEqual(self.agents, self.a_star.agents)
        self.assertEqual([], self.a_star.path)

    def test_check_blocked_square_fails(self):
        self.arena.set_blockage([0], [1])
        status = self.a_star.check_target_location(0, 1)
        self.assertEqual(RoutingStatus.TARGET_BLOCKED, status)

    def test_check_reserved_square_fails(self):
        self.arena.set_reserved([0], [1])
        status = self.a_star.check_target_location(0, 1)
        self.assertEqual(RoutingStatus.TARGET_RESERVED, status)

    def test_route_to_blocked_square_fails(self):
        self.arena.set_blockage([0], [1])
        status = self.a_star.route(self.agents[0], (0, 1))
        self.assertEqual(RoutingStatus.TARGET_BLOCKED, status)

    def test_route_to_reserved_square_fails(self):
        self.arena.set_reserved([0], [1])
        status = self.a_star.route(self.agents[0], (0, 1))
        self.assertEqual(RoutingStatus.TARGET_RESERVED, status)

    def test_initialize_nodes(self):
        start = (0, 0)
        target = (0, 4)
        start_node = AStarNode(start)
        end_node = AStarNode(target)
        self.a_star.initialize_nodes(self.agents[0], target)
        start_eq = start_node == self.a_star.start
        end_eq = end_node == self.a_star.target
        self.assertTrue(start_eq)
        self.assertTrue(end_eq)

    def test_get_new_nodes_in_empty_area(self):
        # initialize the search, and then get neighbouring tiles
        start = (1, 1)
        expected_neighbours = [(2, 1), (1, 2), (0, 1), (1, 0)]
        parent_node = AStarNode(start)
        new_nodes = self.a_star.generate_new_nodes(parent_node)
        self.assertEqual(len(expected_neighbours), len(new_nodes))
        # make sure all of the correct nodes are returned
        for node_location in expected_neighbours:
            test_node = AStarNode(node_location)
            node_exists = test_node in new_nodes
            self.assertTrue(node_exists)

    def test_get_new_nodes_in_corner(self):
        # initialize the search in a corner, and then get neighbouring tiles
        start = (0, 0)
        expected_neighbours = [(0, 1), (1, 0)]
        parent_node = AStarNode(start)
        new_nodes = self.a_star.generate_new_nodes(parent_node)
        self.assertEqual(len(expected_neighbours), len(new_nodes))
        # make sure all of the correct nodes are returned
        for node_location in expected_neighbours:
            test_node = AStarNode(node_location)
            node_exists = test_node in new_nodes
            self.assertTrue(node_exists)

    def test_get_new_nodes_with_blockage(self):
        # initialize the search, set some blockages, and then make sure only the free tiles are returned
        start = (1, 1)
        self.arena.set_blockage([2], [0, 1, 2, 3])
        expected_neighbours = [(1, 2), (0, 1), (1, 0)]
        parent_node = AStarNode(start)
        new_nodes = self.a_star.generate_new_nodes(parent_node)
        self.assertEqual(len(expected_neighbours), len(new_nodes))
        # make sure all of the correct nodes are returned
        for node_location in expected_neighbours:
            test_node = AStarNode(node_location)
            node_exists = test_node in new_nodes
            self.assertTrue(node_exists)

    def test_calculate_heuristic(self):
        start = (1, 1)
        target = (4, 4)
        start_node = AStarNode(start)
        target_node = AStarNode(target)
        heuristic = self.a_star.calculate_heuristic_cost(
            start_node, target_node)
        self.assertEqual(6, heuristic)

    @unittest.skip('debug')
    def test_routing_simple_path(self):
        target = (4, 4)
        status = self.a_star.route(self.agents[0], target)
        self.assertEqual(RoutingStatus.SUCCESS, status)
        # make sure the final nodes are correct
        self.assertTupleEqual((4, 4), self.a_star.node_path[-1].location)

    def test_route_to_tile_with_other_agent_fails(self):
        status = self.a_star.check_target_location(1, 1)
        self.assertEqual(RoutingStatus.TARGET_RESERVED, status)

    def test_calculate_turn_cost_no_factor(self):
        start_node = AStarNode((0, 0))
        node_1 = AStarNode((1, 0), parent=start_node)
        node_2 = AStarNode((2, 0), parent=node_1)
        node_3 = AStarNode((2, 1), parent=node_2)
        node_4 = AStarNode((2, 2), parent=node_3)
        node_5 = AStarNode((3, 2), parent=node_4)
        turn_cost = self.a_star.calculate_turn_cost(node_5)
        self.assertEqual(0, turn_cost)

    def test_calculate_turn_cost_with_weight(self):
        start_node = AStarNode((0, 0))
        self.a_star.turn_factor = 1
        node_1 = AStarNode((1, 0), parent=start_node)
        node_2 = AStarNode((2, 0), parent=node_1)
        node_3 = AStarNode((2, 1), parent=node_2)
        node_4 = AStarNode((2, 2), parent=node_3)
        node_5 = AStarNode((3, 2), parent=node_4)
        turn_cost = self.a_star.calculate_turn_cost(node_5)
        self.assertEqual(2, turn_cost)

    def test_calculate_inline_cost(self):
        self.a_star.inline_factor = 10
        self.arena.set_agent_target(3, 3)
        node = AStarNode((1, 3))
        score = self.a_star.calculate_inline_cost(node)
        self.assertEqual(10, score)

    def test_is_direction_valid(self):
        parents = [(1, 1), (1, 1), (1, 1), (1, 1)]
        children = [(2, 1), (0, 1), (1, 2), (1, 0)]
        main_biases = [
            BiasedDirection.ONLY_X_POSITIVE, BiasedDirection.ONLY_X_NEGATIVE,
            BiasedDirection.ONLY_Y_POSITIVE, BiasedDirection.ONLY_Y_NEGATIVE
        ]
        secondary_biases = [
            BiasedDirection.ONLY_Y_POSITIVE, BiasedDirection.ONLY_Y_NEGATIVE,
            BiasedDirection.ONLY_X_POSITIVE, BiasedDirection.ONLY_X_NEGATIVE
        ]
        for idx in range(len(parents)):
            parent = parents[idx]
            child = children[idx]
            bias = main_biases[idx]
            self.biased_grid[child] = bias
            self.biased_grid[parent] = bias
            self.assertTrue(self.a_star.is_direction_valid(parent, child))
            self.assertFalse(self.a_star.is_direction_valid(child, parent))
            bias = secondary_biases[idx]
            self.biased_grid[child] = bias
            self.biased_grid[parent] = bias
            self.assertFalse(self.a_star.is_direction_valid(parent, child))
class TestMultiAgentAlgorithm(unittest.TestCase):
    def setUp(self):
        time_step = 0.005
        self.arena = Arena(10, 10)
        self.biased_grid = BiasedGrid(self.arena.get_dimensions())
        self.agents = [Agent(0, 0, time_step), Agent(5, 5, time_step)]
        self.algorithm = SingleAgentAlgorithmMock(self.arena, self.agents,
                                                  self.biased_grid)
        self.routing_manager = MultiAgentAlgorithmMock(self.arena, self.agents,
                                                       self.algorithm)

    def tearDown(self):
        pass

    def test_is_simulation_completed_passes_if_final_goal_reached(self):
        self.routing_manager.add_agent_goal(0, (0, 0))
        self.routing_manager.add_agent_goal(1, (5, 5))
        self.assertTrue(self.routing_manager.is_simulation_complete())

    def test_simulation_not_completed_if_final_goal_not_reached(self):
        # add the current location as a segment, but also add a second location for each agent
        self.routing_manager.add_agent_goal(0, (0, 0))
        self.routing_manager.add_agent_goal(1, (5, 5))
        self.routing_manager.add_agent_goal(0, (1, 1))
        self.routing_manager.add_agent_goal(1, (4, 4))
        self.assertFalse(self.routing_manager.is_simulation_complete())

    def test_update_agent_goal(self):
        self.routing_manager.add_agent_goal(0, (0, 0))
        self.routing_manager.add_agent_goal(0, (1, 1))
        self.assertTrue(self.routing_manager.is_agent_at_goal(0))
        self.routing_manager.update_agent_goal(0)
        self.assertTupleEqual((1, 1), self.routing_manager.agent_goals[0][0])
        self.assertFalse(self.routing_manager.is_agent_at_goal(0))
        self.assertFalse(self.routing_manager.is_simulation_complete())

    def test_routing_blockages(self):
        move_x_task = AgentTask(AgentTasks.MOVE, [AgentCoordinates.X, 3])
        move_y_task = AgentTask(AgentTasks.MOVE, [AgentCoordinates.Y, 3])
        self.routing_manager.add_agent_task(0, move_x_task)
        for i in range(1, 3):
            self.assertEqual(TileState.RESERVED,
                             self.arena.get_tile_state(i, 0))
        self.assertEqual(TileState.AGENT_TARGET,
                         self.arena.get_tile_state(3, 0))
        self.routing_manager.add_agent_task(0, move_y_task)
        for i in range(1, 3):
            self.assertEqual(TileState.RESERVED,
                             self.arena.get_tile_state(3, i))
        self.assertEqual(TileState.AGENT_TARGET,
                         self.arena.get_tile_state(3, 3))

    def test_adding_and_completing_task_clears_blockage(self):
        move_x_task = AgentTask(AgentTasks.MOVE, [AgentCoordinates.X, 3])
        self.routing_manager.add_agent_task(0, move_x_task)
        for i in range(1, 3):
            self.assertEqual(TileState.RESERVED,
                             self.arena.get_tile_state(i, 0))
        self.assertEqual(TileState.AGENT_TARGET,
                         self.arena.get_tile_state(3, 0))
        self.routing_manager.signal_agent_event(0, AgentEvent.TASK_COMPLETED)
        for i in range(1, 4):
            self.assertEqual(TileState.FREE, self.arena.get_tile_state(i, 0))

    def test_completing_task_clears_agent_active(self):
        move_x_task = AgentTask(AgentTasks.MOVE, [AgentCoordinates.X, 3])
        self.routing_manager.add_agent_task(0, move_x_task)
        self.routing_manager.signal_agent_event(0, AgentEvent.TASK_COMPLETED)
        self.assertFalse(self.routing_manager.active_agents[0])

    def test_initialize_algorithm(self):
        self.routing_manager.initialize()
        self.assertTrue(self.routing_manager.initialized)

    def test_is_agent_at_goal(self):
        self.routing_manager.add_agent_goal(0, (0, 0))
        self.assertTrue(self.routing_manager.is_agent_at_goal(0))

    def test_start_new_task(self):
        move_x_task = AgentTask(AgentTasks.MOVE, [AgentCoordinates.X, 3])
        self.routing_manager.add_agent_task(0, move_x_task)
        self.routing_manager.start_new_task(0)
        self.assertTrue(self.routing_manager.active_agents[0])
class TestSingleAgentAlgorithm(unittest.TestCase):
    def setUp(self):
        time_step = 0.005
        self.arena = Arena(10, 10)
        self.biased_grid = BiasedGrid(self.arena.get_dimensions())
        self.agents = [Agent(0, 0, time_step), Agent(1, 1, time_step)]
        self.algorithm = SingleAgentAlgorithmMock(self.arena, self.agents,
                                                  self.biased_grid)

    def tearDown(self):
        pass

    def test_reconstruct_empty_path_is_invalid(self):
        self.algorithm.node_path = list()
        status = self.algorithm.create_path()
        self.assertEqual(RoutingStatus.INVALID_PATH, status)

    def test_diagonal_path_is_invalid(self):
        self.algorithm.node_path = [NodeMock((0, 0)), NodeMock((1, 1))]
        status = self.algorithm.create_path()
        self.assertEqual(RoutingStatus.INVALID_PATH, status)

    def test_reconstruct_path(self):
        # force a list of nodes to be the node path
        self.algorithm.node_path = [
            NodeMock((0, 0)),
            NodeMock((0, 1)),
            NodeMock((0, 2)),
            NodeMock((1, 2)),
            NodeMock((2, 2))
        ]
        status = self.algorithm.create_path()
        self.assertEqual(RoutingStatus.SUCCESS, status)
        # The order of the tasks should be: Move X 2, Move Y 2
        task_direction = [AgentCoordinates.Y, AgentCoordinates.X]
        task_distance = [2, 2]
        for idx, task in enumerate(self.algorithm.path):
            self.assertEqual(task_direction[idx], task.args[0])
            self.assertEqual(task_distance[idx], task.args[1])

    def test_reconstruct_path_zig_zag(self):
        # force a list of nodes to be the node path
        self.algorithm.node_path = [
            NodeMock((0, 0)),
            NodeMock((1, 0)),
            NodeMock((1, 1)),
            NodeMock((2, 1)),
            NodeMock((2, 2)),
            NodeMock((3, 2)),
            NodeMock((3, 3)),
            NodeMock((4, 3)),
            NodeMock((4, 4))
        ]
        status = self.algorithm.create_path()
        self.assertEqual(RoutingStatus.SUCCESS, status)
        # this path should contain 8 tasks
        self.assertEqual(8, len(self.algorithm.path))
        # The order of the tasks should be: Move X 1, Move Y 1, Move X 1, Move Y 1
        task_direction = [
            AgentCoordinates.X, AgentCoordinates.Y, AgentCoordinates.X,
            AgentCoordinates.Y, AgentCoordinates.X, AgentCoordinates.Y,
            AgentCoordinates.X, AgentCoordinates.Y
        ]
        task_distance = [1, 1, 1, 1, 1, 1, 1, 1]
        for idx, task in enumerate(self.algorithm.path):
            self.assertEqual(task_direction[idx], task.args[0])
            self.assertEqual(task_distance[idx], task.args[1])
class TestArena(unittest.TestCase):
    def setUp(self):
        # note: this means coordinates go from x = [0-4], y = [0-9]
        self.arena = Arena(5, 10)

    def test_generate_grid(self):
        self.assertEqual(TileState.FREE, self.arena.get_tile_state(4, 9))

    def test_set_blockage(self):
        x_values = list(range(3))
        y_values = [3]
        self.arena.set_blockage(x_values, y_values)
        for x in x_values:
            for y in y_values:
                self.assertEqual(TileState.BLOCKED,
                                 self.arena.get_tile_state(x, y))

    def test_set_reserved(self):
        x_values = list(range(3))
        y_values = [3]
        self.arena.set_reserved(x_values, y_values)
        for x in x_values:
            for y in y_values:
                self.assertEqual(TileState.RESERVED,
                                 self.arena.get_tile_state(x, y))

    def test_get_dimensions(self):
        dimensions = self.arena.get_dimensions()
        self.assertTupleEqual((5, 10), dimensions)

    def test_clear_blockage(self):
        x_values = list(range(3))
        y_values = [3]
        self.arena.set_blockage(x_values, y_values)
        self.arena.clear_blockage(x_values, y_values)
        for x in x_values:
            for y in y_values:
                self.assertEqual(TileState.FREE,
                                 self.arena.get_tile_state(x, y))

    def test_boundary_checking(self):
        x_range = list(range(5))
        y_range = list(range(10))
        # test the upper and lower rows
        for x in x_range:
            self.assertTrue(self.arena.is_boundary_tile(x, 0))
            self.assertTrue(self.arena.is_boundary_tile(x, 9))
        # test the sides
        for y in y_range:
            self.assertTrue(self.arena.is_boundary_tile(0, y))
            self.assertTrue(self.arena.is_boundary_tile(4, y))

    def test_neighbours_at_corners(self):
        corners = [(0, 0), (0, 9), (4, 9), (4, 0)]
        test_neighbours = [[(1, 0), (0, 1)], [(0, 8), (1, 9)], [(3, 9),
                                                                (4, 8)],
                           [(3, 0), (4, 1)]]
        for idx, corner in enumerate(corners):
            neighbours = self.arena.get_neighbours(corner[0], corner[1])
            # each corner should only have two neighbours
            self.assertEqual(2, len(neighbours))
            for check in test_neighbours[idx]:
                self.assertTrue((check in neighbours))

    def test_set_agent_target(self):
        self.arena.set_agent_target(4, 4)
        state = self.arena.get_tile_state(4, 4)
        self.assertEqual(TileState.AGENT_TARGET, state)