Exemple #1
0
 def test_attack_action(self):
     character = Character(state=Undead())
     target = default_human()
     next_action = character.next_action(
         FakeViewpoint([(Vector(1, 1), target)]), BoundingBox.range(5),
         FakeActions())
     assert next_action == Attack(Vector(1, 1))
Exemple #2
0
 def test_move_action(self):
     character = Character(state=Undead())
     environment = FakeViewpoint([(Vector(3, 3), default_human())])
     next_action: Action = character.next_action(environment,
                                                 BoundingBox.range(5),
                                                 FakeActions())
     assert next_action == Move(Vector(1, 1))
Exemple #3
0
    def test_chooses_shortest_best_move(self):
        target_vectors = TargetVectors(
            FakeViewpoint([(Vector(1, 2), default_zombie())]))
        moves = [Vector.ZERO, Vector(1, 0), Vector(2, 0)]

        assert Living().best_move(target_vectors, moves) == Vector.ZERO
        # To make sure we're not lucking out based on the order
        assert Living().best_move(target_vectors,
                                  list(reversed(moves))) == Vector.ZERO
Exemple #4
0
class TestVector:
    def test_no_arg_constructor(self):
        with pytest.raises(TypeError) as exc:
            Vector()  # type: ignore

    def test_single_arg_constructor(self):
        with pytest.raises(TypeError):
            Vector(3)  # type: ignore

    @given(st.integers(), st.integers())
    def test_accepts_two_coordinates(self, dx, dy):
        vector = Vector(dx, dy)
        assert vector.dx == dx
        assert vector.dy == dy

    def test_zero_distance(self):
        assert Vector.ZERO.distance == 0

    @given(vectors())
    def test_vector_distance(self, vector):
        assert vector.distance >= 0

    @given(vectors())
    @example(Vector.ZERO)
    def test_truthiness(self, vector):
        assert bool(vector) == (vector.distance > 0)

    @pytest.mark.parametrize("dx,dy", [(2, 1), (-2, 1), (2, -1), (-2, -1)])
    def test_non_zero_distance(self, dx, dy):
        assert Vector(dx, dy).distance == math.sqrt(5)

    @given(vectors(), vectors())
    @example(Vector(1, 1), Vector(3, 3))
    def test_triangle_inequality(self, a, b):
        sum_distance = (a + b).distance
        distance_sum = a.distance + b.distance

        assert sum_distance < distance_sum or sum_distance == approx(
            distance_sum)

    def test_value_equality(self):
        assert Vector(2, 5) == Vector(2, 5)

    def test_value_inequality(self):
        assert Vector(2, 5) != Vector(2, 3)

    @given(vectors(), vectors())
    def test_addition(self, vector_a, vector_b):
        vector_sum = vector_a + vector_b
        assert vector_sum.dx == vector_a.dx + vector_b.dx
        assert vector_sum.dy == vector_a.dy + vector_b.dy

    @given(vectors(), vectors())
    def test_addition_then_subtraction(self, vector_a, vector_b):
        assert vector_a + vector_b - vector_b == vector_a
        assert vector_a + vector_b - vector_a == vector_b
Exemple #5
0
class TestLivingState:
    def test_life_state(self):
        assert Living().life_state == LifeState.LIVING

    @given(moves=st.lists(vectors(), min_size=1))
    def test_movement_without_zombies(self, moves):
        target_vectors = TargetVectors(FakeViewpoint([]))
        assert Living().best_move(target_vectors,
                                  moves) == min(moves,
                                                key=lambda v: v.distance)

    @given(
        zombie_vectors=st.lists(vectors(), min_size=1),
        moves=st.lists(vectors(), min_size=1),
    )
    @example(
        zombie_vectors=[Vector(dx=0, dy=130),
                        Vector(dx=0, dy=-128)],
        moves=[Vector(dx=0, dy=0),
               Vector(dx=0, dy=1),
               Vector(dx=0, dy=2)],
    )
    def test_movement_with_zombies(self, zombie_vectors, moves):
        target_vectors = TargetVectors(
            FakeViewpoint([(v, default_zombie()) for v in zombie_vectors]))
        best_move = Living().best_move(target_vectors, moves)

        def distance_after_move(move):
            return min((zombie - move).distance for zombie in zombie_vectors)

        best_move_distance = distance_after_move(best_move)
        note(f"Best distance, after {best_move}: {best_move_distance}")

        for move in moves:
            move_distance = distance_after_move(move)
            note(f"Distance after {move}: {move_distance}")

        assert all(best_move_distance >= distance_after_move(move)
                   for move in moves)

    def test_chooses_shortest_best_move(self):
        target_vectors = TargetVectors(
            FakeViewpoint([(Vector(1, 2), default_zombie())]))
        moves = [Vector.ZERO, Vector(1, 0), Vector(2, 0)]

        assert Living().best_move(target_vectors, moves) == Vector.ZERO
        # To make sure we're not lucking out based on the order
        assert Living().best_move(target_vectors,
                                  list(reversed(moves))) == Vector.ZERO

    @given(environments())
    def test_never_attacks(self, environment):
        assert Living().attack(environment) is None

    def test_no_next_state(self):
        assert Living().next_state is None
 def test_viewpoint_multiple_characters(self, char1, char2):
     roster = Roster.for_mapping(
         {
             Point(1, 1): char1,
             Point(2, 0): char2
         },
         area=Area(Point(0, 0), Point(3, 3)),
     )
     viewpoint = Viewpoint(Point(0, 1), roster)
     assert viewpoint.occupied_points_in(
         BoundingBox.range(1)) == {Vector(1, 0)}
     assert viewpoint.occupied_points_in(BoundingBox.range(5)) == {
         Vector(1, 0),
         Vector(2, -1),
     }
Exemple #7
0
    def test_all_paths_blocked(self, zombie):
        """Test that zombies stay still when surrounded by other zombies.

        This effectively functions as a last check that zombies always have
        their own position as a fall-back, and don't register as blocking their
        own non-movement.
        """
        def env_contents(vector):
            return default_zombie() if vector else zombie

        vectors = [Vector(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1]]
        distant_human = [(Vector(2, 2), default_human())]
        zombies_all_around = [(v, env_contents(v)) for v in vectors]

        viewpoint = FakeViewpoint(distant_human + zombies_all_around)
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))

        assert zombie.move(viewpoint, limits) == Vector.ZERO
Exemple #8
0
 def test_alternate_path(self, zombie):
     environment = [
         (Vector(2, 2), default_human()),
         (Vector(1, 1), default_zombie()),
         (Vector(1, 0), default_zombie()),
     ]
     limits = BoundingBox(Vector(-100, -100), Vector(100, 100))
     assert zombie.move(FakeViewpoint(environment), limits) == Vector(0, 1)
Exemple #9
0
    def test_nearest_human(self, zombie):
        environment = [
            (Vector(3, -3), default_human()),
            (Vector(2, 2), default_human()),
            (Vector(-3, 3), default_human()),
        ]
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))

        assert zombie.move(FakeViewpoint(environment), limits) == Vector(1, 1)
Exemple #10
0
    def test_partial_barrier(self):
        # +---+---+---+
        # | m | m |   |
        # +---+---+---+
        # | m | x |   |
        # +---+---+---+
        # | 0 | x |   |
        # +---+---+---+

        character_range = BoundingBox(Vector(0, 0), Vector(3, 3))
        obstacles = {Vector(1, 1), Vector(1, 0)}
        available = available_moves(character_range, obstacles)
        assert available == {
            Vector(0, 0),
            Vector(0, 1),
            Vector(0, 2),
            Vector(1, 2)
        }
Exemple #11
0
 def test_vector_containment(self, vector):
     box = BoundingBox(Vector.ZERO, Vector(1, 1))
     assert (vector in box) == (vector == vector.ZERO)
Exemple #12
0
 def test_empty_box(self):
     box = BoundingBox(Vector.ZERO, Vector.ZERO)
     assert Vector(1, 1) not in box
Exemple #13
0
 def test_negative_box(self):
     box = BoundingBox(Vector.ZERO, Vector(-1, -1))
     assert Vector.ZERO not in box
Exemple #14
0
class TestBoundingBox:
    def test_takes_two_vectors(self):
        BoundingBox(Vector.ZERO, Vector(1, 1))

    def test_empty_box(self):
        box = BoundingBox(Vector.ZERO, Vector.ZERO)
        assert Vector(1, 1) not in box

    def test_negative_box(self):
        box = BoundingBox(Vector.ZERO, Vector(-1, -1))
        assert Vector.ZERO not in box

    @given(vectors())
    def test_vector_containment(self, vector):
        box = BoundingBox(Vector.ZERO, Vector(1, 1))
        assert (vector in box) == (vector == vector.ZERO)

    @given(
        st.builds(BoundingBox, vectors(bound=ITERATION_BOUND),
                  vectors(bound=ITERATION_BOUND)))
    def test_iteration_covers_box(self, box):
        box_vectors = list(box)
        for vector in box:
            assert vector in box_vectors

    @given(
        box=st.builds(BoundingBox, vectors(bound=ITERATION_BOUND),
                      vectors(bound=ITERATION_BOUND)),
        vector=vectors(),
    )
    @example(BoundingBox(Vector(-2, -2), Vector(3, 3)), Vector(2, 3))
    def test_iteration_is_limited_to_box(self, box, vector):
        assume(vector not in box)
        assert vector not in list(box)

    @given(
        boxes=st.lists(st.builds(BoundingBox, vectors(), vectors()),
                       min_size=2),
        vector=vectors(),
    )
    def test_vector_outside_intersection(self, boxes, vector):
        assume(any(vector not in box for box in boxes))
        intersection = reduce(lambda a, b: a.intersect(b), boxes)
        assert vector not in intersection

    @given(vectors_and_containing_boxes())
    def test_vector_inside_intersection(self, vector_and_boxes):
        vector, boxes = vector_and_boxes
        intersection = reduce(lambda a, b: a.intersect(b), boxes)
        assert vector in intersection

    @given(st.integers(min_value=0), vectors())
    @example(radius=10, vector=Vector(10, 10))
    @example(radius=0, vector=Vector(0, 0))
    def test_range(self, radius, vector):
        bounding_box = BoundingBox.range(radius)
        if abs(vector.dx) <= radius and abs(vector.dy) <= radius:
            assert vector in bounding_box
        else:
            assert vector not in bounding_box

    def test_invalid_range(self):
        with pytest.raises(ValueError):
            BoundingBox.range(-1)
Exemple #15
0
 def test_takes_two_vectors(self):
     BoundingBox(Vector.ZERO, Vector(1, 1))
Exemple #16
0
 def test_value_equality(self):
     assert Vector(2, 5) == Vector(2, 5)
Exemple #17
0
 def test_value_inequality(self):
     assert Vector(2, 5) != Vector(2, 3)
Exemple #18
0
 def test_accepts_two_coordinates(self, dx, dy):
     vector = Vector(dx, dy)
     assert vector.dx == dx
     assert vector.dy == dy
Exemple #19
0
 def test_non_zero_distance(self, dx, dy):
     assert Vector(dx, dy).distance == math.sqrt(5)
Exemple #20
0
 def test_no_arg_constructor(self):
     with pytest.raises(TypeError) as exc:
         Vector()  # type: ignore
Exemple #21
0
 def test_single_arg_constructor(self):
     with pytest.raises(TypeError):
         Vector(3)  # type: ignore
Exemple #22
0
class TestZombie:
    @pytest.fixture(scope="session")
    def zombie(self):
        return default_zombie()

    @given(environments_and_limits())
    def test_move_returns_a_vector(self, zombie, environment_and_limits):
        environment, limits = environment_and_limits
        assert isinstance(zombie.move(FakeViewpoint(environment), limits),
                          Vector)

    @given(environments(characters=humans, min_size=1, max_size=1),
           containing_boxes)
    def test_never_moves_away_from_human(self, zombie, environment, limits):
        viewpoint = FakeViewpoint(environment)
        move = zombie.move(viewpoint, limits)
        assert (environment[0][0] -
                move).distance <= environment[0][0].distance

    @given(environments_and_limits(characters=humans, min_chars=1,
                                   max_chars=1))
    def test_move_approaches_single_human(self, zombie,
                                          environment_and_limits):
        environment, limits = environment_and_limits
        assume(environment[0][0].distance > 1)
        move = zombie.move(FakeViewpoint(environment), limits)
        assert (environment[0][0] - move).distance < environment[0][0].distance

    @given(environments_and_limits())
    def test_does_not_move_onto_occupied_space(self, zombie,
                                               environment_and_limits):
        environment, limits = environment_and_limits
        move = zombie.move(FakeViewpoint(environment), limits)
        assert move not in [e[0] for e in environment]

    @given(environments_and_limits())
    def test_moves_up_to_one_space(self, zombie, environment_and_limits):
        environment, limits = environment_and_limits
        move = zombie.move(FakeViewpoint(environment), limits)
        assert abs(move.dx) <= 1
        assert abs(move.dy) <= 1

    @given(environments_and_limits(characters=zombies))
    def test_ignores_zombies(self, zombie, environment_and_limits):
        environment, limits = environment_and_limits
        assert zombie.move(FakeViewpoint(environment), limits) == Vector.ZERO

    @given(environments_and_limits())
    def test_respects_limits(self, zombie, environment_and_limits):
        environment, limits = environment_and_limits
        move = zombie.move(FakeViewpoint(environment), limits)
        assert move in limits

    @given(containing_boxes)
    def test_nothing_nearby(self, zombie, limits):
        assert zombie.move(FakeViewpoint([]), limits) == Vector.ZERO

    def test_nearest_human(self, zombie):
        environment = [
            (Vector(3, -3), default_human()),
            (Vector(2, 2), default_human()),
            (Vector(-3, 3), default_human()),
        ]
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))

        assert zombie.move(FakeViewpoint(environment), limits) == Vector(1, 1)

    def test_blocked_path(self, zombie):
        environment = [
            (Vector(2, 2), default_human()),
            (Vector(1, 1), default_zombie()),
            (Vector(1, 0), default_zombie()),
            (Vector(0, 1), default_zombie()),
        ]
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))
        assert zombie.move(FakeViewpoint(environment), limits) == Vector.ZERO

    def test_all_paths_blocked(self, zombie):
        """Test that zombies stay still when surrounded by other zombies.

        This effectively functions as a last check that zombies always have
        their own position as a fall-back, and don't register as blocking their
        own non-movement.
        """
        def env_contents(vector):
            return default_zombie() if vector else zombie

        vectors = [Vector(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1]]
        distant_human = [(Vector(2, 2), default_human())]
        zombies_all_around = [(v, env_contents(v)) for v in vectors]

        viewpoint = FakeViewpoint(distant_human + zombies_all_around)
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))

        assert zombie.move(viewpoint, limits) == Vector.ZERO

    def test_alternate_path(self, zombie):
        environment = [
            (Vector(2, 2), default_human()),
            (Vector(1, 1), default_zombie()),
            (Vector(1, 0), default_zombie()),
        ]
        limits = BoundingBox(Vector(-100, -100), Vector(100, 100))
        assert zombie.move(FakeViewpoint(environment), limits) == Vector(0, 1)

    @given(
        st.lists(st.tuples(vectors(max_offset=1), humans),
                 min_size=1,
                 max_size=1))
    def test_attack(self, zombie, environment):
        vector = environment[0][0]

        assert zombie.attack(FakeViewpoint(environment)) == vector

    @given(environments(characters=humans))
    @example([(Vector(2, 0), default_human())])
    def test_targets_out_of_range(self, zombie, environment):
        biting_range = BoundingBox(Vector(-1, -1), Vector(2, 2))
        assume(all(e[0] not in biting_range for e in environment))

        assert zombie.attack(FakeViewpoint(environment)) is None
Exemple #23
0
    def test_targets_out_of_range(self, zombie, environment):
        biting_range = BoundingBox(Vector(-1, -1), Vector(2, 2))
        assume(all(e[0] not in biting_range for e in environment))

        assert zombie.attack(FakeViewpoint(environment)) is None
Exemple #24
0
 def test_total_barrier(self):
     obstacles = {Vector(1, y) for y in range(-2, 3)}
     available = available_moves(BoundingBox.range(2), obstacles)
     assert available == set(BoundingBox(Vector(-2, -2), Vector(1, 3)))
Exemple #25
0
 def test_does_not_obstruct_self(self, human):
     environment = FakeViewpoint([(Vector.ZERO, human)])
     limits = BoundingBox(Vector(-100, -100), Vector(100, 100))
     assert human.move(environment, limits) == Vector.ZERO
Exemple #26
0
 def test_does_not_move_in_empty_environment(self, human):
     limits = BoundingBox(Vector(-100, -100), Vector(100, 100))
     assert human.move(FakeViewpoint([]), limits) == Vector.ZERO