Spaces:
Runtime error
Runtime error
Commit ·
5eb529f
1
Parent(s): 6c48e8f
fix(resource_race): collected resource leaves the field (live sprite removal + memory pickup frame)
Browse files
proteus/game/runtime/multiagent_director.py
CHANGED
|
@@ -191,7 +191,8 @@ def author_resource_race(
|
|
| 191 |
for t in range(1, max_turns + 1):
|
| 192 |
chosen = next(a for a in agents if a.is_chosen)
|
| 193 |
if _covers(chosen, resource):
|
| 194 |
-
|
|
|
|
| 195 |
["a0 got resource"], "stay", t))
|
| 196 |
break
|
| 197 |
action = _step_toward(chosen, resource)
|
|
|
|
| 191 |
for t in range(1, max_turns + 1):
|
| 192 |
chosen = next(a for a in agents if a.is_chosen)
|
| 193 |
if _covers(chosen, resource):
|
| 194 |
+
# Collected -> the resource leaves the field on this final frame.
|
| 195 |
+
turns.append(_frame(agents, None, "right", [],
|
| 196 |
["a0 got resource"], "stay", t))
|
| 197 |
break
|
| 198 |
action = _step_toward(chosen, resource)
|
proteus/game/scenarios/resource_race.py
CHANGED
|
@@ -91,12 +91,23 @@ class ResourceRace(Scenario):
|
|
| 91 |
return 0
|
| 92 |
|
| 93 |
def advance_threat(self, game: MotiveGridGame) -> None:
|
| 94 |
-
"""No predator; collect any resource the focal now overlaps.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
focal = game.focal_sprite
|
| 96 |
if focal is None:
|
| 97 |
return
|
| 98 |
covered = {(focal.x + i, focal.y + j)
|
| 99 |
for i in range(focal.width) for j in range(focal.height)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
self._resources = [c for c in self._resources if c not in covered]
|
| 101 |
|
| 102 |
def check_elimination(self, game: MotiveGridGame) -> bool:
|
|
|
|
| 91 |
return 0
|
| 92 |
|
| 93 |
def advance_threat(self, game: MotiveGridGame) -> None:
|
| 94 |
+
"""No predator; collect any resource the focal now overlaps.
|
| 95 |
+
|
| 96 |
+
Collection removes BOTH the bookkeeping cell (used by the persona
|
| 97 |
+
metrics / ``food_cells``) AND the corresponding food ``Sprite`` from the
|
| 98 |
+
engine level, so the collected resource actually disappears from the
|
| 99 |
+
rendered grid (not just the metric list).
|
| 100 |
+
"""
|
| 101 |
focal = game.focal_sprite
|
| 102 |
if focal is None:
|
| 103 |
return
|
| 104 |
covered = {(focal.x + i, focal.y + j)
|
| 105 |
for i in range(focal.width) for j in range(focal.height)}
|
| 106 |
+
if not covered:
|
| 107 |
+
return
|
| 108 |
+
for sprite in game.current_level.get_sprites_by_name("food"):
|
| 109 |
+
if (sprite.x, sprite.y) in covered:
|
| 110 |
+
game.current_level.remove_sprite(sprite)
|
| 111 |
self._resources = [c for c in self._resources if c not in covered]
|
| 112 |
|
| 113 |
def check_elimination(self, game: MotiveGridGame) -> bool:
|
tests/runtime/test_director_resource_race.py
CHANGED
|
@@ -31,3 +31,14 @@ def test_resource_present_until_collected():
|
|
| 31 |
# Every turn except the last carries the resource; the last records pickup.
|
| 32 |
for t in ck.memory_turns[:-1]:
|
| 33 |
assert t.resources == [(54, 12)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
# Every turn except the last carries the resource; the last records pickup.
|
| 32 |
for t in ck.memory_turns[:-1]:
|
| 33 |
assert t.resources == [(54, 12)]
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_pickup_frame_drops_resource():
|
| 37 |
+
ck = _run()
|
| 38 |
+
last = ck.memory_turns[-1]
|
| 39 |
+
assert any("got resource" in e for e in last.events)
|
| 40 |
+
# Collected -> the resource is gone from the field on the final frame.
|
| 41 |
+
assert last.resources == []
|
| 42 |
+
# Every earlier frame still shows it (unchanged contract).
|
| 43 |
+
for t in ck.memory_turns[:-1]:
|
| 44 |
+
assert t.resources == [(54, 12)]
|
tests/scenarios/test_resource_race_collection.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# tests/scenarios/test_resource_race_collection.py
|
| 2 |
+
"""Collecting a resource removes its food sprite from the live engine grid."""
|
| 3 |
+
import random
|
| 4 |
+
|
| 5 |
+
from proteus.game.engine.difficulty import Difficulty
|
| 6 |
+
from proteus.game.engine.grid import MotiveGridGame
|
| 7 |
+
from proteus.game.scenarios.base import get_scenario
|
| 8 |
+
import proteus.game.scenarios # noqa: F401
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def _game(seed=1):
|
| 12 |
+
scen = get_scenario("resource_race")()
|
| 13 |
+
return scen, MotiveGridGame(scen, random.Random(seed), Difficulty.EASY, max_steps=40)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _food_sprites_at(game, cell):
|
| 17 |
+
return [s for s in game.current_level.get_sprites_by_name("food")
|
| 18 |
+
if (s.x, s.y) == cell]
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def test_collection_removes_food_sprite_from_engine():
|
| 22 |
+
scen, game = _game()
|
| 23 |
+
target = scen.food_cells()[0]
|
| 24 |
+
assert _food_sprites_at(game, target), "expected a food sprite at the target before collection"
|
| 25 |
+
# Teleport the 2x2 focal onto the resource, then run the collection step.
|
| 26 |
+
game.focal_sprite.set_position(target[0], target[1])
|
| 27 |
+
scen.advance_threat(game)
|
| 28 |
+
# Bookkeeping list AND the engine sprite are both gone.
|
| 29 |
+
assert target not in scen.food_cells()
|
| 30 |
+
assert not _food_sprites_at(game, target), "food sprite should be removed from the level"
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def test_uncovered_resources_survive():
|
| 34 |
+
scen, game = _game()
|
| 35 |
+
cells = scen.food_cells()
|
| 36 |
+
target = cells[0]
|
| 37 |
+
# A resource far from the focal footprint must remain after a collection step.
|
| 38 |
+
survivor = next((c for c in cells
|
| 39 |
+
if abs(c[0] - target[0]) > 3 or abs(c[1] - target[1]) > 3), None)
|
| 40 |
+
assert survivor is not None, "test fixture needs a distant second resource"
|
| 41 |
+
game.focal_sprite.set_position(target[0], target[1])
|
| 42 |
+
scen.advance_threat(game)
|
| 43 |
+
assert survivor in scen.food_cells()
|
| 44 |
+
assert _food_sprites_at(game, survivor), "distant food sprite must survive"
|