"""Tests der Broadphase (Sweep-and-Prune).""" import random from sandbox.physics import Body, Vector2 from sandbox.physics.broadphase import find_candidate_pairs from tests.helpers import material def _random_scene(seed: int, count: int) -> list[Body]: rng = random.Random(seed) bodies = [] for _ in range(count): position = Vector2(rng.uniform(0, 400), rng.uniform(0, 300)) if rng.random() < 0.5: bodies.append(Body.circle(position, rng.uniform(5, 30), material())) else: bodies.append(Body.box(position, rng.uniform(5, 30), rng.uniform(5, 30), material())) return bodies def _overlap(a: Body, b: Body) -> bool: a_min_x, a_min_y, a_max_x, a_max_y = a.bounds() b_min_x, b_min_y, b_max_x, b_max_y = b.bounds() return a_min_x <= b_max_x and b_min_x <= a_max_x and a_min_y <= b_max_y and b_min_y <= a_max_y def test_matches_brute_force_on_random_scenes() -> None: for seed in range(5): bodies = _random_scene(seed, 60) expected = { (min(a.id, b.id), max(a.id, b.id)) for i, a in enumerate(bodies) for b in bodies[i + 1 :] if _overlap(a, b) } found = [(a.id, b.id) for a, b in find_candidate_pairs(bodies)] assert len(found) == len(set(found)), "kein Paar doppelt" assert set(found) == expected def test_pairs_are_ordered_by_id() -> None: bodies = _random_scene(7, 40) for a, b in find_candidate_pairs(bodies): assert a.id < b.id def test_pairs_of_sleeping_bodies_are_skipped() -> None: a = Body.circle(Vector2(0, 0), 10, material()) b = Body.circle(Vector2(15, 0), 10, material()) c = Body.circle(Vector2(30, 0), 10, material()) a.put_to_sleep() b.put_to_sleep() pairs = {(x.id, y.id) for x, y in find_candidate_pairs([a, b, c])} assert (a.id, b.id) not in pairs # beide schlafen assert (b.id, c.id) in pairs # schlafend + wach wird geprüft