def test_givenPathWithPosition_whenAddVerticallyNonAdjacentPosition_thenThrowInvalidPositionException( self, ): path = Path([Position(1, 3)]) a_position = Position(1, 1) with self.assertRaises(PositionNotAdjacentException): path.add(a_position)
def test_givenEmptyPath_whenAdd_thenPositionIsAddedToPath(self): path = Path([]) a_position = Position(1, 1) path.add(a_position) self.assertEqual(a_position, path[0])
def test_givenPathWithPosition_whenAddAdjacentPosition_thenPositionIsAddedToPath( self, ): path = Path([Position(1, 2)]) a_position = Position(1, 1) path.add(a_position) self.assertEqual(a_position, path[1])
def test_givenExperimentallyFoundBreakingPath_whenCreateMovement_thenDoNotThrow( self, ): pass a_breaking_path = Path([ Position(148, 238), Position(149, 238), Position(150, 238), Position(151, 238), Position(152, 238), Position(153, 238), Position(154, 238), Position(155, 238), Position(156, 238), Position(157, 238), Position(158, 238), Position(159, 238), Position(160, 238), Position(161, 238), Position(161, 239), ]) an_orientation = CardinalOrientation.EAST.value try: movements = self.movement_factory.create_movements( a_breaking_path, an_orientation) except Exception as e: self.fail( f"MovementFactory.create_movements threw exception '{e}'")
def test_givenStartAndEndPosition_whenFindPathWithCartesianCoordinates_thenFlipsCoordinatesAndFindsPath( self, ): starting_position = Position(2, 1) ending_position = Position(5, 1) expected_path = Path([ Position(2, 1), Position(3, 1), Position(3, 2), Position(3, 3), Position(3, 4), Position(3, 5), Position(3, 6), Position(4, 6), Position(5, 6), Position(5, 5), Position(5, 4), Position(5, 3), Position(5, 2), Position(5, 1), ]) actual_path = (self.a_start_algorithm. find_shortest_path_with_cartesian_coordinates( starting_position, ending_position)) self.assertEqual(expected_path, actual_path)
def test_givenPathOfOnePosition_whenCreateMovement_thenReturnSingleMovementPath( self, ): a_one_position_path = Path([Position(0, 0)]) movements = self.movement_factory.create_movements( a_one_position_path, self.AN_ORIENTATION) self.assertEqual(len(movements), 1)
def test_givenPathWithTwoPositions_whenGetSecondItem_thenSecondPositionIsReturned( self, ): first_position = Position(1, 1) second_position = Position(1, 2) path = Path([first_position, second_position]) actual_position = path[1] self.assertEqual(second_position, actual_position)
def test_givenPathWithTwoPositions_whenGettingLengthOfPath_thenReturnTwo( self): first_position = Position(1, 1) second_position = Position(1, 2) path = Path([first_position, second_position]) path_length = len(path) self.assertEqual(2, path_length)
def test_givenStraightPathWithYDecreasing_whenCreateMovementsWithSouthOrientation_thenReturnSingleMovementWithCorrectDirection( self, ): a_path = Path([ Position(1, 4), Position(1, 3), Position(1, 2), Position(1, 1), ]) forward_movement = self.movement_factory.create_movements( a_path, CardinalOrientation.SOUTH.value)[0] self.assertEqual(Direction.FORWARD, forward_movement.get_direction())
def test_givenStraightPathWithXDecreasing_whenCreateMovementsWithSouthOrientation_thenReturnSingleMovementWithCorrectDirection( self, ): a_path = Path([ Position(4, 1), Position(3, 1), Position(2, 1), Position(1, 1), ]) left_movement = self.movement_factory.create_movements( a_path, CardinalOrientation.SOUTH.value)[0] self.assertEqual(Direction.LEFT, left_movement.get_direction())
def test_givenStraightPathWithYDecreasing_whenCreateMovementsWithEastOrientation_thenReturnSingleMovementWithCorrectDirection( self, ): a_path = Path([ Position(1, 4), Position(1, 3), Position(1, 2), Position(1, 1), ]) right_movement = self.movement_factory.create_movements( a_path, CardinalOrientation.EAST.value)[0] self.assertEqual(Direction.RIGHT, right_movement.get_direction())
def test_givenStraightPathWithXIncreasing_whenCreateMovementsWithEastOrientation_thenReturnSingleMovementWithCorrectDirection( self, ): a_path = Path([ Position(1, 1), Position(2, 1), Position(3, 1), Position(4, 1), ]) backward_movement = self.movement_factory.create_movements( a_path, CardinalOrientation.EAST.value)[0] self.assertEqual(Direction.BACKWARDS, backward_movement.get_direction())
def test_givenSingleLinePath_whenCreateMovements_thenSingleMovementIsCreated( self): a_path = Path( [Position(1, 0), Position(1, 1), Position(1, 2), Position(1, 4)]) movements = self.movement_factory.create_movements( a_path, CardinalOrientation.WEST.value) self.assertEqual(1, len(movements))
def test_givenOrientationFarFromCardinalOrientation_whenCreateMovements_thenRaiseInvalidOrientationException( self, ): a_far_orientation = Orientation(188) a_path = Path([ Position(1, 4), Position(1, 3), Position(1, 2), Position(1, 1), ]) creating_movements = lambda: self.movement_factory.create_movements( a_path, a_far_orientation) with self.assertRaises(InvalidOrientationException): creating_movements()
def test_givenOrientationCloseToCardinalOrientationSouth_whenCreateMovements_thenReturnMovementWithRightDirection( self, ): a_close_orientation = Orientation(91) a_path = Path([ Position(1, 4), Position(1, 3), Position(1, 2), Position(1, 1), ]) expected_direction = Direction.FORWARD movement = self.movement_factory.create_movements( a_path, a_close_orientation)[0] self.assertEqual(movement.get_direction(), expected_direction)
def _reconstruct_path( self, came_from: Dict[GridLocation, GridLocation], start: GridLocation, goal: GridLocation, ) -> Path: current: GridLocation = goal path: List[Position] = [] while current != start: current_y_coordinate, current_x_coordinate = current path.append(Position(current_x_coordinate, current_y_coordinate)) current = came_from[current] start_y_coordinate, start_x_coordinate = start path.append(Position(start_x_coordinate, start_y_coordinate)) path.reverse() return Path(path)
def test_givenStraightPathWithFivePoints_whenCreateMovements_thenASingleMovementWithDistanceFiveIsCreated( self, ): a_path = Path([ Position(1, 0), Position(1, 1), Position(1, 2), Position(1, 4), Position(1, 5), ]) expected_distance = Distance(distance=5) movements = self.movement_factory.create_movements( a_path, CardinalOrientation.WEST.value) movement_distance = movements[0].get_distance() self.assertEqual(expected_distance, movement_distance)
def test_givenPathWithNinetyDegreeTurnAndGoingBackwards_whenCreateMovements_thenTwoMovementsAreCreated( self, ): a_path = Path([ Position(1, 3), Position(1, 2), Position(1, 1), Position(1, 0), Position(2, 0), Position(3, 0), Position(4, 0), ]) movements = self.movement_factory.create_movements( a_path, CardinalOrientation.WEST.value) self.assertEqual(2, len(movements))
def test_givenPathWithTurn_whenCreateMovements_thenTwoMovementsWithRightDistancesAreCreated( self, ): a_path = Path([ Position(1, 1), Position(2, 1), Position(3, 1), Position(4, 1), Position(4, 2), Position(4, 3), Position(4, 4), ]) expected_first_distance = Distance(distance=4) expected_second_distance = Distance(distance=3) movements = self.movement_factory.create_movements( a_path, CardinalOrientation.WEST.value) first_movement_distance = movements[0].get_distance() second_movement_distance = movements[1].get_distance() self.assertEqual(expected_first_distance, first_movement_distance) self.assertEqual(expected_second_distance, second_movement_distance)
def _split_path_in_sub_paths(self, full_path: Path) -> List[Path]: sub_paths = list() if not self._path_has_turn(full_path): sub_paths.append(full_path) return sub_paths current_position = 1 path_length = len(full_path) + 1 current_path = Path([]) while current_position < path_length - 1: is_current_direction_vertical = self._are_positions_moving_vertically( full_path[current_position - 1], full_path[current_position]) if is_current_direction_vertical: while is_current_direction_vertical and current_position < path_length: current_path.add(full_path[current_position - 1]) is_current_direction_vertical = self._is_current_direction_vertical( is_current_direction_vertical, current_position, path_length, full_path, ) current_position += 1 else: while (not is_current_direction_vertical and current_position < path_length): current_path.add(full_path[current_position - 1]) is_current_direction_vertical = self._is_current_direction_vertical( is_current_direction_vertical, current_position, path_length, full_path, ) current_position += 1 sub_paths.append(current_path) current_path = Path([]) return sub_paths
def test_givenEmptyPath_whenGetItem_thenIndexErrorIsRaised(self): path = Path([]) with self.assertRaises(IndexError): _ = path[0]