proejct commit

This commit is contained in:
2026-09-24 15:45:31 +02:00
commit 82d52be8a5
63 changed files with 8748 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
"""Tests des Schlafmodus (Inseln, Einschlafen, Aufwecken)."""
from dataclasses import replace
from sandbox.config import PHYSICS
from sandbox.physics import Body, Contact, Vector2, collide
from sandbox.physics.sleep import UnionFind, find_islands, update_sleep, wake_touched_bodies
from tests.helpers import material
def _circle(x: float, y: float = 0.0, radius: float = 10.0) -> Body:
return Body.circle(Vector2(x, y), radius, material())
def _contacts(*pairs: tuple[Body, Body]) -> list[Contact]:
contacts = [collide(a, b) for a, b in pairs]
assert all(contact is not None for contact in contacts)
return [contact for contact in contacts if contact is not None]
def test_union_find_merges_sets() -> None:
union_find = UnionFind([1, 2, 3, 4, 5])
union_find.union(1, 2)
union_find.union(3, 4)
union_find.union(2, 4)
assert union_find.find(1) == union_find.find(3) == union_find.find(4)
assert union_find.find(5) != union_find.find(1)
def test_touching_bodies_form_islands_but_walls_do_not_connect_them() -> None:
a, b, c, d = _circle(0), _circle(15), _circle(30), _circle(200)
floor = Body.wall(Vector2(0, -1), -5, material()) # berührt alle Kreise
contacts = _contacts((a, b), (b, c), (a, floor), (d, floor))
islands = find_islands([a, b, c, d], contacts)
assert [set(island) for island in islands] == [{a, b, c}, {d}]
def test_an_island_sleeps_only_when_all_its_bodies_rest() -> None:
config = replace(PHYSICS, time_to_sleep=0.5)
resting, moving = _circle(0), _circle(15)
moving.velocity = Vector2(50, 0)
contacts = _contacts((resting, moving))
for _ in range(100):
update_sleep([resting, moving], contacts, 0.01, config)
assert resting.sleep_time >= 0.5
assert not resting.sleeping # der bewegte Nachbar hält die Insel wach
moving.velocity = Vector2(0, 0)
for _ in range(60):
update_sleep([resting, moving], contacts, 0.01, config)
assert resting.sleeping
assert moving.sleeping
def test_waking_one_body_wakes_its_whole_island() -> None:
a, b, c, outsider = _circle(0), _circle(15), _circle(30), _circle(300)
island = [a, b, c]
for body in island:
body.put_to_sleep(island)
outsider.put_to_sleep()
c.wake()
assert not any(body.sleeping for body in island)
assert all(body.sleep_island is None for body in island)
assert outsider.sleeping
def test_touching_a_sleeper_wakes_and_reports_its_whole_island() -> None:
a, b, c = _circle(0), _circle(15), _circle(30)
island = [b, c]
for body in island:
body.put_to_sleep(island)
woken = wake_touched_bodies(_contacts((a, b)))
assert set(woken) == {b, c}
assert not c.sleeping
def test_held_bodies_keep_their_island_awake() -> None:
held, other = _circle(0), _circle(15)
held.held = True
contacts = _contacts((held, other))
for _ in range(200):
update_sleep([held, other], contacts, 0.01, PHYSICS)
assert not held.sleeping
assert not other.sleeping
assert held.sleep_time == 0
def test_sleepers_touched_by_awake_bodies_are_woken_but_not_by_walls() -> None:
sleeper, awake = _circle(0), _circle(15)
sleeper.put_to_sleep()
floor = Body.wall(Vector2(0, -1), -5, material())
lonely = _circle(300)
lonely.put_to_sleep()
both_asleep = _circle(500)
both_asleep.put_to_sleep()
neighbour = _circle(515)
neighbour.put_to_sleep()
woken = wake_touched_bodies(
_contacts((sleeper, awake), (lonely, floor), (both_asleep, neighbour))
)
assert woken == [sleeper]
assert not sleeper.sleeping
assert lonely.sleeping
assert both_asleep.sleeping