P23-03: 生活の観察
This commit is contained in:
@@ -5,6 +5,74 @@ const Stream := preload("res://tests/fixtures/p23-03/diagnostic_stream.gd")
|
||||
var checks := 0
|
||||
var failures := 0
|
||||
|
||||
class QueueWorld extends RefCounted:
|
||||
func get_bounds() -> Dictionary:
|
||||
return {&"min_x": -1, &"max_x": 2, &"min_y": 0, &"max_y": 1}
|
||||
func is_walkable(cell: Vector3i) -> bool:
|
||||
return cell.y == 0 and cell.x >= -1 and cell.x <= 2
|
||||
func get_occupant(_cell: Vector3i) -> StringName:
|
||||
return &""
|
||||
|
||||
class QueueLift extends RefCounted:
|
||||
var layer := 0
|
||||
func get_report() -> Dictionary:
|
||||
var trips: Array = []
|
||||
for i: int in 3:
|
||||
trips.append({&"state": PathService.ELEVATOR_REQUEST_QUEUED, &"from": Vector3i(0,0,layer),
|
||||
&"actor_id": "guest:q%d" % i, &"enqueued_at": i})
|
||||
return {&"shafts": [{&"shaft_id": &"wide", &"stops": [Vector3i(0,0,layer), Vector3i(0,1,layer)],
|
||||
&"width": 2, &"capacity": 4, &"boarded": [], &"visual_floor": 0.3,
|
||||
&"operational": true, &"phase": &"PICKUP"}], &"trips": trips}
|
||||
|
||||
class QueueRuntime extends RefCounted:
|
||||
var world_service := QueueWorld.new()
|
||||
var elevators := QueueLift.new()
|
||||
|
||||
func repair28_geometry() -> void:
|
||||
var view := WorldPreview.new()
|
||||
view.size = Vector2(408,332)
|
||||
var fixture := QueueRuntime.new()
|
||||
view._runtime = fixture
|
||||
root.add_child(view)
|
||||
for layer: int in [0,1]:
|
||||
view.layer_mode = layer as WorldPreview.LayerMode
|
||||
fixture.elevators.layer = layer
|
||||
var model: Dictionary = view._observe_queues()
|
||||
expect(model[&"shaft_footprint"].has(Vector3i(1,0,layer)), "width-2 interior belongs to shaft")
|
||||
expect(model[&"queue_positions"].size() == 1 and model[&"queue_hidden"].size() == 2, "shaft stops outward lane and retains overflow")
|
||||
var badge: Dictionary = model[&"landing_badges"][0]
|
||||
expect(badge[&"members"].size() == badge[&"visible_count"] + badge[&"overflow"], "no queue member lost")
|
||||
model.merge({&"boarded": {}, &"elevator_tracks": {}, &"paused": true})
|
||||
var cabins: Array[Dictionary] = view._observe_elevators(model)
|
||||
expect(cabins.size() == 1, "active-layer cabin remains visible")
|
||||
for at: Vector2 in model[&"queue_positions"].values():
|
||||
for cell: Vector3i in model[&"shaft_footprint"]:
|
||||
expect(not view.get_cell_rect(cell).has_point(at), "queue anchor outside full footprint")
|
||||
expect(not cabins[0][&"rect"].has_point(at), "queue anchor outside empty cabin")
|
||||
expect(cabins[0][&"passenger_count"] == 0 and cabins[0][&"passengers"].is_empty(), "empty cabin has no passenger")
|
||||
expect(cabins[0][&"operational"] and not cabins[0][&"doors_open"] and cabins[0][&"phase"] == &"PICKUP", "typed moving cabin state")
|
||||
for operational: bool in [true,false]:
|
||||
for phase: StringName in [&"IDLE", &"BOARDING", &"PICKUP"]:
|
||||
var shaft: Dictionary = fixture.elevators.get_report()[&"shafts"][0]
|
||||
shaft[&"operational"] = operational
|
||||
shaft[&"phase"] = phase
|
||||
var text := Presentation.elevator_label(shaft)
|
||||
expect(text.contains("0/4人") and text.contains(String(phase)), "count and phase visible")
|
||||
expect(text.begins_with("運転" if operational else "停止"), "operation visible beyond lamp")
|
||||
expect(text.contains(" 開 " if operational and phase != &"PICKUP" else " 閉 "), "doors visible beyond lamp")
|
||||
var obstacles: Array[Rect2] = [Rect2(20,0,20,90), Rect2(45,80,20,14)]
|
||||
var segments := view._traffic_segments(Rect2(10,85,60,5), Rect2(0,0,80,96), obstacles)
|
||||
var area := 0.0
|
||||
for segment: Rect2 in segments:
|
||||
area += segment.get_area()
|
||||
for obstacle: Rect2 in obstacles:
|
||||
expect(not segment.intersects(obstacle), "traffic never crosses cabin or badge")
|
||||
expect(is_equal_approx(area, 100.0), "traffic preserves all uncovered area")
|
||||
var covering: Array[Rect2] = [Rect2(0,80,80,16)]
|
||||
var fallback := view._traffic_segments(Rect2(10,85,60,5), Rect2(0,0,80,96), covering)
|
||||
expect(fallback.size() == 1 and fallback[0] == Rect2(10,0,60,5), "shaft-column density remains visible")
|
||||
view.free()
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("run")
|
||||
|
||||
@@ -25,6 +93,7 @@ func run() -> void:
|
||||
return
|
||||
var clock: Variant = root.get_node("GameClock")
|
||||
clock.set_paused(true)
|
||||
repair28_geometry()
|
||||
# Isolated real typed components test state labels, without claiming gameplay.
|
||||
var labels: Dictionary = {}
|
||||
for state: int in FacilityInstance.State.values():
|
||||
@@ -123,7 +192,7 @@ func run() -> void:
|
||||
var report := view.get_life_observation_report()
|
||||
expect(not report.is_empty(), "actual drawing published an observation")
|
||||
expect(report.get(&"observation_serial", -1) == report.get(&"overlay_consumed_serial", -2), "LifeOverlay consumed this observation")
|
||||
expect(report.get(&"overlay_passes", []) == [&"traffic", &"actors"], "traffic drawn before actors")
|
||||
expect(report.get(&"overlay_passes", []) == [&"traffic", &"cabins", &"actors"], "traffic drawn before cabins and actors")
|
||||
var indices: Array = report.get(&"overlay_child_indices", [])
|
||||
expect(indices.size() == 3 and indices[0] < indices[1] and indices[1] < indices[2], "LifeOverlay above inactive art and below lens")
|
||||
# The getter exposes the last actual draw and must not create another model.
|
||||
|
||||
Reference in New Issue
Block a user