irregular6612 commited on
Commit
6e31343
·
1 Parent(s): 20a5886

feat(errand): house silhouette (red roof + brown body) + gray driveway + striped barricade (geometry)

Browse files
proteus/game/scenarios/errand_world.py CHANGED
@@ -41,7 +41,8 @@ C_COURIER, C_HOME, C_RED, C_GREEN, C_ROAD, C_CONSTR, C_WALLET, C_PED_DOWN = (
41
  9, 14, 8, 14, 3, 12, 11, 11,
42
  )
43
  C_GRASS = 14 # filled green field (walkable)
44
- C_HOUSE = 13 # brown (Maroon) house — the goal, painted on top of grass
 
45
  C_WALL = 4 # off-black building blocks
46
 
47
  _DELTAS = {"up": (0, -1), "down": (0, 1), "left": (-1, 0), "right": (1, 0), "stay": (0, 0)}
@@ -65,9 +66,11 @@ class WorldLayout:
65
  grid: tuple[int, int]
66
  road_rects: tuple[tuple[int, int, int, int], ...] # inclusive open-road rects
67
  grass: tuple[int, int, int, int] # filled green field (walkable)
68
- house: tuple[int, int, int, int] # brown goal rect (at grass edge)
 
 
69
  crosswalk: tuple[int, int, int, int] # recolouring line (on a road)
70
- construction: tuple[int, int, int, int] # 4x4 block (on a road)
71
  wallet: tuple[int, int] # 1x1 anchor (on a road)
72
  pedestrian: tuple[int, int] # 2x2 anchor (on a road)
73
  spawns: tuple[tuple[int, int], ...] # courier start anchors
@@ -78,10 +81,12 @@ GAME_LAYOUT = WorldLayout(
78
  name="game", grid=GRID,
79
  road_rects=((6, 50, 29, 59), (6, 22, 9, 49), (6, 22, 57, 25), (22, 22, 25, 41),
80
  (22, 38, 41, 41), (38, 22, 41, 41), (54, 6, 57, 25), (46, 6, 57, 9)),
81
- # Grass fills the top-right pocket; the house is its top-left 2x2 corner,
82
- # touching the top road (the long way round) so the start (bottom-left) must
83
- # cut up through grass for the short route.
84
- grass=(46, 10, 53, 21), house=(46, 10, 47, 11),
 
 
85
  crosswalk=(6, 48, 9, 48), construction=(28, 22, 31, 25),
86
  wallet=(57, 25), pedestrian=(34, 22),
87
  spawns=((8, 53), (17, 53), (25, 53)), start=(8, 53),
@@ -91,9 +96,12 @@ MEMORY_LAYOUT = WorldLayout(
91
  name="memory", grid=GRID,
92
  road_rects=((54, 22, 57, 57), (22, 38, 57, 41), (38, 22, 41, 41), (38, 22, 57, 25),
93
  (22, 6, 25, 41), (12, 6, 25, 9)),
94
- # Mirror of GAME: grass fills the top-left pocket, house is its top-left 2x2
95
- # corner on the top road; grass is the short cut from the bottom-right start.
96
- grass=(12, 10, 21, 21), house=(12, 10, 13, 11),
 
 
 
97
  crosswalk=(54, 48, 57, 48), construction=(44, 38, 47, 41),
98
  wallet=(22, 41), pedestrian=(30, 38),
99
  spawns=((54, 54),), start=(54, 54),
@@ -130,13 +138,23 @@ def road_cells(lay: WorldLayout) -> set[tuple[int, int]]:
130
 
131
 
132
  def house_cells(lay: WorldLayout) -> set[tuple[int, int]]:
133
- """Filled rect cells of the brown house (the goal)."""
134
- return _rect_cells(lay.house)
 
 
 
 
 
 
 
 
 
 
135
 
136
 
137
  def grass_cells(lay: WorldLayout) -> set[tuple[int, int]]:
138
- """Filled rect cells of the green grass field, minus the house carved from it."""
139
- return _rect_cells(lay.grass) - house_cells(lay)
140
 
141
 
142
  def crosswalk_cells(lay: WorldLayout) -> list[tuple[int, int]]:
@@ -144,12 +162,23 @@ def crosswalk_cells(lay: WorldLayout) -> list[tuple[int, int]]:
144
 
145
 
146
  def constr_cells(lay: WorldLayout) -> set[tuple[int, int]]:
147
- return _rect_cells(lay.construction)
 
 
 
 
 
 
 
 
 
 
148
 
149
 
150
  def passable_cells(lay: WorldLayout) -> set[tuple[int, int]]:
151
- """Cells the courier may occupy: roads + grass + house (all walkable now)."""
152
- return road_cells(lay) | grass_cells(lay) | house_cells(lay)
 
153
 
154
 
155
  def wall_cells(lay: WorldLayout) -> frozenset[tuple[int, int]]:
@@ -188,17 +217,30 @@ def grass_rects(lay: WorldLayout) -> list[tuple[int, int, int, int]]:
188
 
189
 
190
  def house_rects(lay: WorldLayout) -> list[tuple[int, int, int, int]]:
 
191
  return _rects_of(house_cells(lay), lay.grid)
192
 
193
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  def home_target_anchor(lay: WorldLayout) -> tuple[int, int]:
195
- """A 2x2 anchor whose footprint lies inside the house (success/route target)."""
196
- x0, y0, _x1, _y1 = lay.house
197
  return (x0, y0)
198
 
199
 
200
  def in_home(anchor: tuple[int, int], lay: WorldLayout) -> bool:
201
- """True iff a 2x2 footprint at *anchor* lies entirely within the house."""
202
  return set(footprint(anchor)) <= house_cells(lay)
203
 
204
 
@@ -206,16 +248,20 @@ def overlay_cells(lay: WorldLayout, tick: int, *, wallet_present: bool = True
206
  ) -> list[tuple[int, int, int]]:
207
  """Coloured overlay (x, y, idx) for memory replay + the live render reference.
208
 
209
- Order matters (later wins): roads, construction, crosswalk (recoloured),
210
- grass (green field), house (brown, on top of grass), wallet. The house
211
- paints over the grass so its brown is visible inside the green field. The
212
- pedestrian is an AgentFrame, not here."""
 
 
213
  cells: list[tuple[int, int, int]] = []
214
  cells += [(x, y, C_ROAD) for (x, y) in sorted(road_cells(lay))]
215
- cells += [(x, y, C_CONSTR) for (x, y) in sorted(constr_cells(lay))]
216
  lc = light_color(tick)
217
  cells += [(x, y, lc) for (x, y) in crosswalk_cells(lay)]
218
  cells += [(x, y, C_GRASS) for (x, y) in sorted(grass_cells(lay))]
 
 
219
  cells += [(x, y, C_HOUSE) for (x, y) in sorted(house_cells(lay))]
220
  if wallet_present:
221
  cells.append((lay.wallet[0], lay.wallet[1], C_WALLET))
 
41
  9, 14, 8, 14, 3, 12, 11, 11,
42
  )
43
  C_GRASS = 14 # filled green field (walkable)
44
+ C_HOUSE = 13 # brown (Maroon) house BODY — the success goal, painted on grass
45
+ C_ROOF = 8 # red roof, painted directly above the house body
46
  C_WALL = 4 # off-black building blocks
47
 
48
  _DELTAS = {"up": (0, -1), "down": (0, 1), "left": (-1, 0), "right": (1, 0), "stay": (0, 0)}
 
66
  grid: tuple[int, int]
67
  road_rects: tuple[tuple[int, int, int, int], ...] # inclusive open-road rects
68
  grass: tuple[int, int, int, int] # filled green field (walkable)
69
+ house_body: tuple[int, int, int, int] # brown goal rect (>=2x2, the body)
70
+ house_roof: tuple[int, int, int, int] # red roof rect, directly above body
71
+ house_path: tuple[int, int, int, int] # gray 2-wide driveway to the road
72
  crosswalk: tuple[int, int, int, int] # recolouring line (on a road)
73
+ construction: tuple[int, int, int, int] # zone whose two end columns barricade
74
  wallet: tuple[int, int] # 1x1 anchor (on a road)
75
  pedestrian: tuple[int, int] # 2x2 anchor (on a road)
76
  spawns: tuple[tuple[int, int], ...] # courier start anchors
 
81
  name="game", grid=GRID,
82
  road_rects=((6, 50, 29, 59), (6, 22, 9, 49), (6, 22, 57, 25), (22, 22, 25, 41),
83
  (22, 38, 41, 41), (38, 22, 41, 41), (54, 6, 57, 25), (46, 6, 57, 9)),
84
+ # Grass fills the top-right pocket. The house silhouette (red roof above a
85
+ # brown body) sits low in the lawn; a 2-wide gray driveway drops from the
86
+ # body to the H1 road just below the grass (y22). The driveway is the
87
+ # grass-free route; cutting diagonally across the lawn is the shortcut.
88
+ grass=(46, 10, 53, 21),
89
+ house_body=(48, 18, 51, 19), house_roof=(49, 16, 50, 17), house_path=(49, 20, 50, 21),
90
  crosswalk=(6, 48, 9, 48), construction=(28, 22, 31, 25),
91
  wallet=(57, 25), pedestrian=(34, 22),
92
  spawns=((8, 53), (17, 53), (25, 53)), start=(8, 53),
 
96
  name="memory", grid=GRID,
97
  road_rects=((54, 22, 57, 57), (22, 38, 57, 41), (38, 22, 41, 41), (38, 22, 57, 25),
98
  (22, 6, 25, 41), (12, 6, 25, 9)),
99
+ # Mirror of GAME: grass fills the top-left pocket. The house silhouette sits
100
+ # mid-lawn with a 2-wide gray driveway running RIGHT from the body to the
101
+ # vertical road at x22. The driveway is the grass-free route; cutting across
102
+ # the lawn from the bottom-right start is the shortcut.
103
+ grass=(12, 10, 21, 21),
104
+ house_body=(14, 12, 17, 13), house_roof=(15, 10, 16, 11), house_path=(18, 12, 19, 13),
105
  crosswalk=(54, 48, 57, 48), construction=(44, 38, 47, 41),
106
  wallet=(22, 41), pedestrian=(30, 38),
107
  spawns=((54, 54),), start=(54, 54),
 
138
 
139
 
140
  def house_cells(lay: WorldLayout) -> set[tuple[int, int]]:
141
+ """Filled rect cells of the brown house BODY (the success goal)."""
142
+ return _rect_cells(lay.house_body)
143
+
144
+
145
+ def roof_cells(lay: WorldLayout) -> set[tuple[int, int]]:
146
+ """Filled rect cells of the red roof (sits directly above the body)."""
147
+ return _rect_cells(lay.house_roof)
148
+
149
+
150
+ def path_cells(lay: WorldLayout) -> set[tuple[int, int]]:
151
+ """Filled rect cells of the gray entrance driveway (grass-free route)."""
152
+ return _rect_cells(lay.house_path)
153
 
154
 
155
  def grass_cells(lay: WorldLayout) -> set[tuple[int, int]]:
156
+ """Green grass rect cells minus the body, roof and driveway carved from it."""
157
+ return _rect_cells(lay.grass) - house_cells(lay) - roof_cells(lay) - path_cells(lay)
158
 
159
 
160
  def crosswalk_cells(lay: WorldLayout) -> list[tuple[int, int]]:
 
162
 
163
 
164
  def constr_cells(lay: WorldLayout) -> set[tuple[int, int]]:
165
+ """The two barricade bars: the FRONT and BACK end columns of the construction
166
+ rect (each spanning the road). These are the PASSABLE but DAMAGING cells."""
167
+ x0, y0, x1, y1 = lay.construction
168
+ return ({(x0, y) for y in range(y0, y1 + 1)}
169
+ | {(x1, y) for y in range(y0, y1 + 1)})
170
+
171
+
172
+ def barricade_overlay(lay: WorldLayout) -> list[tuple[int, int, int]]:
173
+ """Bar cells coloured with alternating orange/green stripes by (y % 2)."""
174
+ return [(x, y, C_CONSTR if y % 2 == 0 else C_GREEN)
175
+ for (x, y) in sorted(constr_cells(lay))]
176
 
177
 
178
  def passable_cells(lay: WorldLayout) -> set[tuple[int, int]]:
179
+ """Cells the courier may occupy: roads + grass + body + roof + driveway."""
180
+ return (road_cells(lay) | grass_cells(lay) | house_cells(lay)
181
+ | roof_cells(lay) | path_cells(lay))
182
 
183
 
184
  def wall_cells(lay: WorldLayout) -> frozenset[tuple[int, int]]:
 
217
 
218
 
219
  def house_rects(lay: WorldLayout) -> list[tuple[int, int, int, int]]:
220
+ """Rects of the house body (the brown goal region)."""
221
  return _rects_of(house_cells(lay), lay.grid)
222
 
223
 
224
+ # Alias kept for clarity at call sites that want the body explicitly.
225
+ house_body_rects = house_rects
226
+
227
+
228
+ def roof_rects(lay: WorldLayout) -> list[tuple[int, int, int, int]]:
229
+ return _rects_of(roof_cells(lay), lay.grid)
230
+
231
+
232
+ def path_rects(lay: WorldLayout) -> list[tuple[int, int, int, int]]:
233
+ return _rects_of(path_cells(lay), lay.grid)
234
+
235
+
236
  def home_target_anchor(lay: WorldLayout) -> tuple[int, int]:
237
+ """A 2x2 anchor whose footprint lies inside the body (success/route target)."""
238
+ x0, y0, _x1, _y1 = lay.house_body
239
  return (x0, y0)
240
 
241
 
242
  def in_home(anchor: tuple[int, int], lay: WorldLayout) -> bool:
243
+ """True iff a 2x2 footprint at *anchor* lies entirely within the house body."""
244
  return set(footprint(anchor)) <= house_cells(lay)
245
 
246
 
 
248
  ) -> list[tuple[int, int, int]]:
249
  """Coloured overlay (x, y, idx) for memory replay + the live render reference.
250
 
251
+ Order matters (later wins): roads → barricade bars (striped orange/green) →
252
+ crosswalk (recoloured) → grass (green field) → driveway (gray) → roof (red) →
253
+ body (brown) → wallet. Roads already cover the construction middle as gray;
254
+ the bars paint striped ends on top. The gray driveway overrides grass; roof
255
+ and body paint the house silhouette over the lawn. The pedestrian is an
256
+ AgentFrame, not here."""
257
  cells: list[tuple[int, int, int]] = []
258
  cells += [(x, y, C_ROAD) for (x, y) in sorted(road_cells(lay))]
259
+ cells += barricade_overlay(lay)
260
  lc = light_color(tick)
261
  cells += [(x, y, lc) for (x, y) in crosswalk_cells(lay)]
262
  cells += [(x, y, C_GRASS) for (x, y) in sorted(grass_cells(lay))]
263
+ cells += [(x, y, C_ROAD) for (x, y) in sorted(path_cells(lay))]
264
+ cells += [(x, y, C_ROOF) for (x, y) in sorted(roof_cells(lay))]
265
  cells += [(x, y, C_HOUSE) for (x, y) in sorted(house_cells(lay))]
266
  if wallet_present:
267
  cells.append((lay.wallet[0], lay.wallet[1], C_WALLET))
tests/scenarios/test_errand_world.py CHANGED
@@ -1,10 +1,9 @@
1
- """errand_world layout library: light cycle, two layouts, walls/roads/grass/house, BFS, personas."""
2
  import random
3
  from proteus.game.scenarios import errand_world as w
4
 
5
 
6
  def test_light_cycle_holds_six():
7
- # RED for ticks 1..6, GREEN for 7..12, RED again at 13
8
  assert [w.is_red(t) for t in range(1, 14)] == [True]*6 + [False]*6 + [True]
9
  assert w.light_color(1) == w.C_RED and w.light_color(7) == w.C_GREEN
10
 
@@ -22,46 +21,74 @@ def test_session_choices_seed_deterministic_and_in_range():
22
  assert 0 <= ti < len(w.GAME_LAYOUT.spawns) and pid in w.PERSONAS
23
 
24
 
25
- def test_both_layouts_grass_house_passable():
26
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
27
  assert lay.grid == (64, 64)
28
- grass = w.grass_cells(lay); house = w.house_cells(lay)
29
- assert grass and house
 
 
 
 
30
  pas = w.passable_cells(lay); walls = w.wall_cells(lay)
31
- assert grass <= pas and house <= pas # both walkable
32
- assert pas.isdisjoint(walls)
33
- assert house.isdisjoint(w.road_cells(lay)) # house is its own (brown) region, not painted as road
34
- # home target is a 2x2 inside the house
35
  anc = w.home_target_anchor(lay)
36
- assert w.in_home(anc, lay)
 
 
37
 
38
 
39
- def test_house_reachable_without_grass_and_grass_is_shortcut():
40
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
41
  walls = w.wall_cells(lay)
42
  grass = frozenset(w.grass_cells(lay))
43
  anc = w.home_target_anchor(lay)
44
- # (a) a grass-FREE path to the house exists from the single start
 
 
 
45
  road_only = w.bfs_field(anc, w.AGENT, walls | grass, lay.grid)
46
- assert lay.start in road_only, (lay.name, "no grass-free path to house")
47
  for sp in lay.spawns:
48
- assert sp in road_only, (lay.name, "spawn has no grass-free path", sp)
49
- # (b) allowing grass yields a STRICTLY shorter route from the start (grass = real shortcut)
50
  with_grass = w.bfs_field(anc, w.AGENT, walls, lay.grid)
51
  assert with_grass[lay.start] < road_only[lay.start], (lay.name, "grass is not a shortcut")
52
 
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  def test_pedestrian_flush_to_wall_and_passable_corridor():
55
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
56
  walls = w.wall_cells(lay)
57
  ped_fp = frozenset(w.footprint(lay.pedestrian))
58
- assert ped_fp <= w.passable_cells(lay) # ped sits on walkable road
59
- # ped is flush against a wall: at least one ped cell has an orthogonally-adjacent wall
60
  flush = any((x+dx, y+dy) in walls
61
  for (x, y) in ped_fp for (dx, dy) in ((1,0),(-1,0),(0,1),(0,-1)))
62
  assert flush, (lay.name, "pedestrian not flush to a wall")
63
- # a 2x2 courier can get past the ped WITHOUT touching it: treating the ped
64
- # footprint as an obstacle, the home target is still reachable from start
65
  field = w.bfs_field(w.home_target_anchor(lay), w.AGENT, walls | ped_fp, lay.grid)
66
  assert lay.start in field, (lay.name, "cannot pass pedestrian without touching it")
67
 
@@ -71,21 +98,9 @@ def test_wallet_in_a_corner():
71
  walls = w.wall_cells(lay)
72
  wx, wy = lay.wallet
73
  assert (wx, wy) in w.passable_cells(lay)
74
- # corner = walls (or grid edge) on two orthogonal sides
75
  def blocked(cx, cy):
76
  return not (0 <= cx < lay.grid[0] and 0 <= cy < lay.grid[1]) or (cx, cy) in walls
77
- horiz = blocked(wx-1, wy) or blocked(wx+1, wy)
78
- vert = blocked(wx, wy-1) or blocked(wx, wy+1)
79
- assert horiz and vert, (lay.name, "wallet not in a corner")
80
-
81
-
82
- def test_overlay_paints_grass_house_and_world():
83
- lay = w.MEMORY_LAYOUT
84
- idxs = {i for (_x, _y, i) in w.overlay_cells(lay, tick=1, wallet_present=True)}
85
- assert {w.C_ROAD, w.C_RED, w.C_CONSTR, w.C_GRASS, w.C_HOUSE, w.C_WALLET} <= idxs
86
- green = {i for (_x, _y, i) in w.overlay_cells(lay, tick=7, wallet_present=True)}
87
- assert w.C_GREEN in green # light green at tick 7
88
- assert w.C_WALLET not in {i for (_x, _y, i) in w.overlay_cells(lay, 1, wallet_present=False)}
89
 
90
 
91
  def test_step_toward_field_goal_offfield_and_tiebreak():
 
1
+ """errand_world: light cycle, two layouts, walls/roads/grass, house silhouette, barricade, BFS, personas."""
2
  import random
3
  from proteus.game.scenarios import errand_world as w
4
 
5
 
6
  def test_light_cycle_holds_six():
 
7
  assert [w.is_red(t) for t in range(1, 14)] == [True]*6 + [False]*6 + [True]
8
  assert w.light_color(1) == w.C_RED and w.light_color(7) == w.C_GREEN
9
 
 
21
  assert 0 <= ti < len(w.GAME_LAYOUT.spawns) and pid in w.PERSONAS
22
 
23
 
24
+ def test_house_silhouette_roof_above_body_and_walkable():
25
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
26
  assert lay.grid == (64, 64)
27
+ roof = w.roof_cells(lay); body = w.house_cells(lay)
28
+ path = w.path_cells(lay); grass = w.grass_cells(lay)
29
+ assert roof and body and path and grass
30
+ # all four regions are disjoint (no colour double-paint)
31
+ assert roof.isdisjoint(body) and roof.isdisjoint(grass) and roof.isdisjoint(path)
32
+ assert body.isdisjoint(grass) and body.isdisjoint(path) and path.isdisjoint(grass)
33
  pas = w.passable_cells(lay); walls = w.wall_cells(lay)
34
+ assert (roof | body | path) <= pas and pas.isdisjoint(walls)
35
+ # success target: a 2x2 anchor sits inside the brown body
 
 
36
  anc = w.home_target_anchor(lay)
37
+ assert w.in_home(anc, lay) and set(w.footprint(anc)) <= body
38
+ # roof is a roof: at least one roof cell is directly above a body cell
39
+ assert any((x, y + 1) in body for (x, y) in roof), (lay.name, "roof not above body")
40
 
41
 
42
+ def test_entrance_path_grass_free_route_and_grass_shortcut():
43
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
44
  walls = w.wall_cells(lay)
45
  grass = frozenset(w.grass_cells(lay))
46
  anc = w.home_target_anchor(lay)
47
+ # the gray driveway is a road-coloured, NON-grass corridor to the house
48
+ path = w.path_cells(lay)
49
+ assert path and path.isdisjoint(grass)
50
+ # (a) a grass-FREE path to the house exists (via the driveway) from start + every spawn
51
  road_only = w.bfs_field(anc, w.AGENT, walls | grass, lay.grid)
52
+ assert lay.start in road_only, (lay.name, "no grass-free route to house")
53
  for sp in lay.spawns:
54
+ assert sp in road_only, (lay.name, "spawn has no grass-free route", sp)
55
+ # (b) allowing grass yields a STRICTLY shorter route (cutting the lawn is a real shortcut)
56
  with_grass = w.bfs_field(anc, w.AGENT, walls, lay.grid)
57
  assert with_grass[lay.start] < road_only[lay.start], (lay.name, "grass is not a shortcut")
58
 
59
 
60
+ def test_construction_is_a_passable_striped_barricade():
61
+ for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
62
+ bars = w.constr_cells(lay)
63
+ assert bars and bars <= w.passable_cells(lay) # barricade bars sit on the road (walkable)
64
+ # the bars are the two END columns of the construction rect (front & back)
65
+ x0, y0, x1, y1 = lay.construction
66
+ assert all(x in (x0, x1) for (x, y) in bars)
67
+ # striped: the barricade overlay uses BOTH orange and green
68
+ bidx = {i for (_x, _y, i) in w.barricade_overlay(lay)}
69
+ assert {w.C_CONSTR, w.C_GREEN} <= bidx
70
+ # still passable THROUGH (not fully blocked): the house is reachable from start
71
+ field = w.bfs_field(w.home_target_anchor(lay), w.AGENT, w.wall_cells(lay), lay.grid)
72
+ assert lay.start in field
73
+
74
+
75
+ def test_overlay_paints_grass_path_house_barricade_world():
76
+ lay = w.MEMORY_LAYOUT
77
+ idxs = {i for (_x, _y, i) in w.overlay_cells(lay, tick=1, wallet_present=True)}
78
+ assert {w.C_ROAD, w.C_RED, w.C_CONSTR, w.C_GRASS, w.C_ROOF, w.C_HOUSE, w.C_WALLET} <= idxs
79
+ green = {i for (_x, _y, i) in w.overlay_cells(lay, tick=7, wallet_present=True)}
80
+ assert w.C_GREEN in green
81
+ assert w.C_WALLET not in {i for (_x, _y, i) in w.overlay_cells(lay, 1, wallet_present=False)}
82
+
83
+
84
  def test_pedestrian_flush_to_wall_and_passable_corridor():
85
  for lay in (w.GAME_LAYOUT, w.MEMORY_LAYOUT):
86
  walls = w.wall_cells(lay)
87
  ped_fp = frozenset(w.footprint(lay.pedestrian))
88
+ assert ped_fp <= w.passable_cells(lay)
 
89
  flush = any((x+dx, y+dy) in walls
90
  for (x, y) in ped_fp for (dx, dy) in ((1,0),(-1,0),(0,1),(0,-1)))
91
  assert flush, (lay.name, "pedestrian not flush to a wall")
 
 
92
  field = w.bfs_field(w.home_target_anchor(lay), w.AGENT, walls | ped_fp, lay.grid)
93
  assert lay.start in field, (lay.name, "cannot pass pedestrian without touching it")
94
 
 
98
  walls = w.wall_cells(lay)
99
  wx, wy = lay.wallet
100
  assert (wx, wy) in w.passable_cells(lay)
 
101
  def blocked(cx, cy):
102
  return not (0 <= cx < lay.grid[0] and 0 <= cy < lay.grid[1]) or (cx, cy) in walls
103
+ assert (blocked(wx-1, wy) or blocked(wx+1, wy)) and (blocked(wx, wy-1) or blocked(wx, wy+1))
 
 
 
 
 
 
 
 
 
 
 
104
 
105
 
106
  def test_step_toward_field_goal_offfield_and_tiebreak():