def test_runs_away_from_zombie(self, human, environment_and_limits): environment, limits = environment_and_limits # Make sure there's actually room to run away assume(limits.intersect(BoundingBox.range(1)) == BoundingBox.range(1)) move = human.move(FakeViewpoint(environment), limits) zombie_vector = environment[0][0] assert (zombie_vector - move).distance > zombie_vector.distance
class Undead: life_state = LifeState.UNDEAD movement_range = BoundingBox.range(1) attack_range = BoundingBox.range(1) next_state = None def attack(self, target_vectors: SupportsNearestHuman) -> Optional[Vector]: nearest_human = target_vectors.nearest_human if nearest_human is not None and nearest_human in self.attack_range: return nearest_human else: return None def best_move( self, target_vectors: SupportsNearestHuman, available_moves: Iterable[Vector] ) -> Vector: nearest_human = target_vectors.nearest_human if nearest_human: def move_rank(move: Vector) -> Tuple[float, float]: assert nearest_human is not None return ((nearest_human - move).distance, move.distance) return min(available_moves, key=move_rank) else: return shortest(available_moves) def __eq__(self, other: object) -> bool: return isinstance(other, Undead)
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), }
def test_state_change_action(self): character = Character(state=Dead(age=20)) viewpoint = FakeViewpoint([]) next_action = character.next_action(viewpoint, BoundingBox.range(5), FakeActions()) assert next_action == StateChange(Undead())
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))
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))
class Dead: def __init__(self, age: int = 0): self._age = age life_state = LifeState.DEAD movement_range = BoundingBox.range(0) _resurrection_age: ClassVar[int] = 20 def attack(self, target_vectors: TargetVectors) -> Optional[Vector]: return None def best_move( self, target_vectors: TargetVectors, available_moves: Iterable[Vector] ) -> Vector: if Vector.ZERO not in available_moves: raise ValueError("Zero move unavailable for dead character") return Vector.ZERO @property def next_state(self) -> State: if self._age >= self._resurrection_age: return Undead() else: return Dead(self._age + 1) def __eq__(self, other: object) -> bool: return isinstance(other, Dead) and self._age == other._age
class Living: life_state = LifeState.LIVING movement_range = BoundingBox.range(2) next_state = None def attack(self, target_vectors: TargetVectors) -> Optional[Vector]: return None def best_move( self, target_vectors: TargetVectors, available_moves: Iterable[Vector] ) -> Vector: def nearest_zombie(move: Vector) -> Optional[Vector]: if (nearest := target_vectors.nearest_zombie_to(move)) is not None: return nearest - move else:
def test_invalid_range(self): with pytest.raises(ValueError): BoundingBox.range(-1)
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_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)))
def test_viewpoint_single_character(self, character): roster = Roster.for_mapping({Point(1, 1): character}, area=Area(Point(0, 0), Point(2, 2))) viewpoint = Viewpoint(Point(1, 1), roster) assert viewpoint.occupied_points_in( BoundingBox.range(2)) == {Vector.ZERO}
def test_empty_viewpoint(self): characters: Mapping[Point, Any] = {} roster = Roster.for_mapping(characters, area=Area(Point(0, 0), Point(2, 2))) viewpoint = Viewpoint(Point(1, 1), roster) assert viewpoint.occupied_points_in(BoundingBox.range(2)) == set()