def test_simple(self): pos = Dim2D(5, 5) circle = Circle(pos, 10) self.assertEqual(circle.centre, Dim2D(5, 5)) self.assertEqual(circle.radius, 10) self.assertEqual(str(circle), "centre: (x: 5, y: 5), radius: 10") self.assertEqual(circle.get_position(), Dim2D(5, 5))
def test_a_star_search_simple(self): end_point = Dim2D(7, 6) a_star_functions = AStarFunctions( heuristic_function=Dim2D.get_manathan_distance, weight_function=Dim2D.get_manathan_distance, ) correct_path_list = list( Dim2D.convert_candiates_to_dimensions([ # fmt: off (0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 5), (5, 5), (6, 5), (7, 5), (7, 6), # fmt: on ])) neighbour_data = NeighbourData(NeighbourType.CROSS) self.assertSequenceEqual( self.simple_search_object.a_star_search(end_point, a_star_functions, neighbour_data), correct_path_list, )
def test_convert_candiates_to_dimensions(self): candidates = [(2, 3), (0, 0), (-4, -5)] dimensions = Dim2D.convert_candiates_to_dimensions(candidates) for index, dimension in enumerate(dimensions): self.assertEqual( dimension, Dim2D(candidates[index][0], candidates[index][1]) )
def get_four_corner_points(self): x, y = self.top_left_corner return ( Dim2D(x, y), Dim2D(x + self.width, y), Dim2D(x, y + self.height), Dim2D(x + self.width, y + self.height), )
def complex_function(value, **extra_parameters): point1 = extra_parameters["point1"] point2 = extra_parameters["point2"] if Dim2D.get_manathan_distance(value, point1) > 10: return 20 if Dim2D.get_manathan_distance(value, point2) < 5: return 50 return Dim2D.get_manathan_distance( value, point1 ) + Dim2D.get_manathan_distance(value, point2)
def get_random_edge_point(grid_size): four_sides = ["top", "bottom", "left", "right"] chosen_side = four_sides[random.randint(0, len(four_sides) - 1)] return { "top": Dim2D(random.randint(0, grid_size.x - 1), 0), "bottom": Dim2D(random.randint(0, grid_size.x - 1), grid_size.y - 1), "left": Dim2D(0, random.randint(0, grid_size.y - 1)), "right": Dim2D(grid_size.x - 1, random.randint(0, grid_size.y - 1)), }[chosen_side]
def get_neighbour_function_4_connectivity( position: Dim2D, is_position_valid_function: Callable[[Dim2D, bool, bool], bool], neighbour_data: NeighbourData = NeighbourData(), ) -> Iterator[Tuple[Dim2D, float]]: x, y = position.x, position.y for new_position in (Dim2D(x - 1, y), Dim2D(x, y - 1)): is_valid_position = is_position_valid_function( new_position, neighbour_data.should_block, neighbour_data.should_reach, ) if is_valid_position: yield new_position, -1
def __init__(self, shape: Shape2D, velocity=Dim2D(0, 0), acceleration=Dim2D(0, 0), mass=None): self.shape = shape self._position = shape.get_position() self._velocity = velocity self._acceleration = acceleration self._jerk = Dim2D(0, 0) if mass is not None: check_positive_value(mass) self._mass = mass self._momentum = self._calculate_momentum()
def test_check_boundaries(self): top_left_corner = Dim2D(0, 0) rectangle = Rectangle(top_left_corner, 200, 100) self.assertTrue(rectangle.is_inside_boundaries(Dim2D(2, 3))) self.assertTrue(rectangle.is_inside_boundaries(Dim2D(199, 99))) self.assertTrue(rectangle.is_inside_boundaries(Dim2D(100, 99))) self.assertTrue(rectangle.is_inside_boundaries(Dim2D(100, 75))) self.assertFalse(rectangle.is_inside_boundaries(Dim2D(199, 100))) self.assertFalse(rectangle.is_inside_boundaries(Dim2D(202, 100))) self.assertFalse(rectangle.is_inside_boundaries(Dim2D(-1, 3))) self.assertFalse(rectangle.is_inside_boundaries(Dim2D(-1, -4)))
def test_get_neighbours_cross(self): pos = Dim2D(1, 1) poses_dic = dict(Neighbour.get_neighbours_cross(pos, lambda *_: True)) self.assertEqual(len(poses_dic), 4) self.assertIn(Dim2D(0, 1), poses_dic) self.assertEqual(poses_dic[Dim2D(0, 1)], 1) self.assertIn(Dim2D(1, 2), poses_dic) self.assertEqual(poses_dic[Dim2D(1, 2)], 1) self.assertIn(Dim2D(2, 1), poses_dic) self.assertEqual(poses_dic[Dim2D(2, 1)], 1) self.assertIn(Dim2D(1, 0), poses_dic) self.assertEqual(poses_dic[Dim2D(1, 0)], 1)
def test_depth_first_search_with_thread(self): correct_path_list = list( Dim2D.convert_candiates_to_dimensions( # fmt: off [ (0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 9), (1, 8), (1, 7), (1, 6), (1, 5), (1, 4), (1, 3), (1, 2), (1, 1), (1, 0), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 9), (3, 8), (3, 7), (3, 6), (3, 5), (3, 4), (3, 3), (3, 2), (3, 1), (3, 0), (4, 5), (5, 5), (5, 4), (5, 3), (5, 2), (5, 1), (5, 0), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (5, 9), (5, 8), (5, 7), (5, 6), (4, 9), (7, 9), (7, 8), (7, 7), (7, 6), (7, 5), (7, 4), (7, 3), (7, 2), (7, 1), (7, 0), (8, 0), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8), (8, 9), (9, 9), (9, 8), (9, 7), (9, 6), (9, 5), (9, 4), (9, 3), (9, 2), (9, 1), (9, 0) ] # fmt: on )) neighbour_data = NeighbourData(NeighbourType.CROSS) dfs = self.simple_search_object.depth_first_search( neighbour_data, runs_with_thread=True) dfs.start() dfs.event_set() dfs.run() dfs.join() path = [node.position for node in dfs.get_closed_set()] self.assertSequenceEqual(path, correct_path_list)
def test_simple(self): pos = Dim2D(2, 3) self.assertEqual(pos.x, 2) self.assertEqual(pos.y, 3) x, y = pos self.assertEqual(x, 2) self.assertEqual(y, 3)
def test_all_motion_fields(self): motion = Motion2D( self.point, velocity=Dim2D(2, 2), acceleration=Dim2D(1, -1), mass=6.5 ) self.assertEqual(motion.velocity, Dim2D(2, 2)) self.assertEqual(motion.acceleration, Dim2D(1, -1)) self.assertEqual(motion.mass, 6.5) self.assertEqual(motion.momentum, Dim2D(13, 13)) self.assertEqual( str(motion), ( "Position: (x: 3, y: 5)\nVelocity: (x: 2, y: 2)\n" "Acceleration: (x: 1, y: -1)\nMass: 6.5\n" "Momentum: (x: 13.0, y: 13.0)" ), )
def get_labels_graph(self): new_grid = [] for y, row in enumerate(self.graph.raw_data_handler.raw_data): row_list = [] for x, _ in enumerate(row): row_list.append(self._nodes[Dim2D(x, y)].label_value) new_grid.append(row_list) return new_grid
def test_a_star_search_with_heuristic(self): end_point = Dim2D(7, 6) def custom_heuristic_function(pos1, _): risk_value = 0 if pos1 == Dim2D(4, 5): risk_value = 100 return risk_value a_star_functions = AStarFunctions( heuristic_function=custom_heuristic_function, weight_function=Dim2D.get_manathan_distance, ) correct_path_list = list( Dim2D.convert_candiates_to_dimensions([ # fmt: off (0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (7, 8), (7, 7), (7, 6), # fmt: on ])) neighbour_data = NeighbourData(NeighbourType.CROSS) self.assertSequenceEqual( self.simple_search_object.a_star_search(end_point, a_star_functions, neighbour_data), correct_path_list, )
def generate_graph_search( example_function: Callable[[], List[List[Any]]], start_point: Dim2D = Dim2D(0, 0), ) -> GraphSearch: raw_data_handler = RawDataHandler(example_function()) blocking_values = (1, ) graph = Graph(raw_data_handler, Shape2DType.RECTANGLE, blocking_values) return GraphSearch(graph, start_point)
def update_blocking_positions(blocking_values: Tuple) -> Tuple: positions: List[Dim2D] = [] if not blocking_values: return tuple(positions) for y, row in enumerate(self.raw_data_handler.raw_data): for x, value in enumerate(row): if value in blocking_values: positions.append(Dim2D(x, y)) return tuple(positions)
def test_multiply(self): vec1 = Dim2D(2, 3) vec2 = Dim2D(-1, 1) const = 5 self.assertEqual(vec1.vectoral_multiply(vec2), Dim2D(-2, 3)) self.assertEqual(vec2.vectoral_multiply(vec1), Dim2D(-2, 3)) self.assertEqual(vec1.vectoral_multiply(vec1), Dim2D(4, 9)) self.assertEqual(vec1.constant_multiply(const), Dim2D(10, 15)) self.assertEqual(vec2.constant_multiply(const), Dim2D(-5, 5))
def test_divide(self): vec1 = Dim2D(2, 3) vec2 = Dim2D(-1, 1) const = 5 self.assertEqual(vec1.vectoral_divide(vec2), Dim2D(-2, 3)) self.assertEqual(vec2.vectoral_divide(vec1), Dim2D(-1 / 2, 1 / 3)) self.assertEqual(vec1.vectoral_divide(vec1), Dim2D(1, 1)) self.assertEqual(vec1.constant_divide(const), Dim2D(2 / 5, 3 / 5)) self.assertEqual(vec2.constant_divide(const), Dim2D(-1 / 5, 1 / 5))
def test_circle_vs_circle_intersection_check(self): circle1 = Circle(Dim2D(3, 3), 2) circle2 = Circle(Dim2D(1, 1), 2) circle3 = Circle(Dim2D(-2, -2), 2) circle4 = Circle(Dim2D(2, 2), 1.5) self.assertTrue( Circle.circle_vs_circle_intersection_check(circle1, circle2)) self.assertTrue( Circle.circle_vs_circle_intersection_check( # pylint: disable=arguments-out-of-order circle2, circle1)) self.assertFalse( Circle.circle_vs_circle_intersection_check(circle1, circle3)) self.assertFalse( Circle.circle_vs_circle_intersection_check(circle2, circle3)) self.assertTrue( Circle.circle_vs_circle_intersection_check(circle1, circle4)) self.assertTrue( Circle.circle_vs_circle_intersection_check(circle2, circle4)) self.assertFalse( Circle.circle_vs_circle_intersection_check(circle3, circle4))
def get_neighbours_cross( position: Dim2D, is_position_valid_function: Callable[[Dim2D, bool, bool], bool], neighbour_data: NeighbourData = NeighbourData(), ) -> Iterator[Tuple[Dim2D, float]]: x, y = position.x, position.y for distance in range(1, neighbour_data.radius + 1): for new_position in ( Dim2D(x + distance, y), Dim2D(x - distance, y), Dim2D(x, y + distance), Dim2D(x, y - distance), ): is_valid_position = is_position_valid_function( new_position, neighbour_data.should_block, neighbour_data.should_reach, ) if is_valid_position: yield new_position, distance
def create_rectangle_canvas(graph_data: GraphData) -> List[List]: raw_data: List = [] for y in range(graph_data.grid_size.y): row_raw_data: List = [] for x in range(graph_data.grid_size.x): TkinterSingleton.create_rectangle_at(Dim2D(x, y), graph_data.tile_size, Colour.BLACK) row_raw_data.append(0) raw_data.append(row_raw_data) return raw_data
def test_a_star_search_no_path(self): end_point = Dim2D(7, 6) a_star_functions = AStarFunctions( heuristic_function=Dim2D.get_manathan_distance, weight_function=Dim2D.get_manathan_distance, ) correct_path_list = [] neighbour_data = NeighbourData(NeighbourType.CROSS) self.assertSequenceEqual( self.blocked_search_object.a_star_search(end_point, a_star_functions, neighbour_data), correct_path_list, )
def test_simple_raw_data(self): def stringfy_data(data): for idx, row in enumerate(data): data[idx] = [str(value) for value in row] return data raw_data = example_simple() raw_data_handler = RawDataHandler(raw_data) self.assertTrue(raw_data_handler.raw_data, example_simple()) self.assertTrue(str(raw_data_handler), stringfy_data(example_simple())) chosen_position = Dim2D(4, 0) self.assertTrue(raw_data_handler.get_value(chosen_position), "1") raw_data_handler.set_value(chosen_position, "5") self.assertTrue(raw_data_handler.get_value(chosen_position), "5")
def test_simple(self): top_left_corner = Dim2D(0, 1) rec = Rectangle(top_left_corner, 20, 30) self.assertEqual(rec.top_left_corner, Dim2D(0, 1)) self.assertEqual(rec.width, 20) self.assertEqual(rec.height, 30) self.assertEqual( str(rec), "top_left_corner = (x: 0, y: 1), width x height: 20x30") self.assertEqual(rec.get_position(), Dim2D(0, 1)) four_corner_points = (Dim2D(0, 1), Dim2D(20, 1), Dim2D(0, 31), Dim2D(20, 31)) self.assertEqual(rec.get_four_corner_points(), four_corner_points)
def get_neighbours_square( position: Dim2D, is_position_valid_function: Callable[[Dim2D, bool, bool], bool], neighbour_data: NeighbourData = NeighbourData(), ) -> Iterator[Tuple[Dim2D, float]]: x, y = position.x, position.y for y_distance in range(-neighbour_data.radius, neighbour_data.radius + 1): for x_distance in range(-neighbour_data.radius, neighbour_data.radius + 1): new_position = Dim2D(x + x_distance, y + y_distance) is_not_self_position = not (x_distance == 0 and y_distance == 0) is_valid_position = is_position_valid_function( new_position, neighbour_data.should_block, neighbour_data.should_reach, ) if is_not_self_position and is_valid_position: yield new_position, abs(x_distance) + abs(y_distance)
def setUp(self): def generate_graph_search( example_function: Callable[[], List[List[Any]]], start_point: Dim2D = Dim2D(0, 0), ) -> GraphSearch: raw_data_handler = RawDataHandler(example_function()) blocking_values = (1, ) graph = Graph(raw_data_handler, Shape2DType.RECTANGLE, blocking_values) return GraphSearch(graph, start_point) self.simple_search_object = generate_graph_search(example_simple) self.blocked_search_object = generate_graph_search( example_blocked_in_the_middle) self.half_maze_search_object = generate_graph_search(example_half_maze, start_point=Dim2D( 1, 1))
def test_wiki_example(self): raw_data_handler = RawDataHandler(example_wiki_ccl()) graph = Graph(raw_data_handler, Shape2DType.RECTANGLE, blocking_values=[0]) labeller = ConnectedComponentLabelling(graph, NeighbourType.CONNECTIVITY_EIGHT) labeller.first_pass() first_pass_data = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 3, 3, 3, 3, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 3, 3, 3, 0, 0, 3, 3, 0], [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 3, 3, 3, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 3, 0, 0, 0, 3, 3, 0], [0, 0, 0, 0, 0, 0, 6, 6, 5, 3, 0, 0, 7, 3, 3, 3, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ] self.assertEqual(labeller.get_labels_graph(), first_pass_data) labeller.second_pass() second_pass_data = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 4, 4, 0, 0, 4, 4, 0], [0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 4, 4, 4, 4, 0, 0], [0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0], [0, 0, 2, 2, 2, 2, 0, 0, 0, 4, 4, 4, 0, 0, 4, 4, 0], [0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 4, 4, 4, 0, 0, 0], [0, 0, 2, 2, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4, 0], [0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ] self.assertEqual(labeller.get_labels_graph(), second_pass_data) regions = labeller.get_regions() self.assertEqual(len(regions), 3) self.assertTrue(Dim2D(0, 0) in regions[0]) self.assertTrue(Dim2D(8, 3) in regions[0]) self.assertTrue(Dim2D(11, 6) in regions[0]) self.assertTrue(Dim2D(1, 2) in regions[2]) self.assertTrue(Dim2D(4, 4) in regions[2]) self.assertTrue(Dim2D(15, 1) in regions[4]) self.assertTrue(Dim2D(13, 5) in regions[4])
def test_randomized_depth_first_search(self): # Have the same seed to test randomized output random.seed(42) correct_path_list = list( Dim2D.convert_candiates_to_dimensions([ # fmt: off (0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (3, 2), (3, 3), (2, 3), (1, 3), (0, 3), (0, 2), (0, 1), (1, 1), (1, 2), (0, 4), (1, 4), (1, 5), (2, 5), (3, 5), (3, 6), (2, 6), (2, 7), (2, 8), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (6, 8), (5, 8), (5, 7), (5, 6), (5, 5), (6, 5), (7, 5), (7, 6), (7, 7), (7, 8), (8, 8), (8, 9), (7, 9), (9, 9), (9, 8), (9, 7), (9, 6), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (9, 2), (9, 1), (8, 1), (8, 0), (9, 0), (7, 0), (7, 1), (7, 2), (6, 2), (6, 3), (7, 3), (7, 4), (6, 4), (5, 4), (5, 3), (5, 2), (5, 1), (5, 0), (6, 0), (6, 1), (9, 3), (9, 4), (9, 5), (8, 7), (6, 7), (6, 6), (4, 5), (2, 9), (1, 9), (1, 8), (1, 7), (0, 7), (0, 6), (1, 6), (0, 5), (0, 8), (0, 9), (3, 7), (3, 4), (2, 4), # fmt: on ])) neighbour_data = NeighbourData(NeighbourType.CROSS, random_output=True) dfs = self.simple_search_object.depth_first_search(neighbour_data) dfs.run_without_thread() path = [node.position for node in dfs.get_closed_set()] self.assertSequenceEqual(path, correct_path_list)
def custom_heuristic_function(pos1, _): risk_value = 0 if pos1 == Dim2D(4, 5): risk_value = 100 return risk_value