P23-03: 生活の観察
This commit is contained in:
@@ -1455,6 +1455,40 @@ def actor_track_transit(report, key, cell):
|
||||
return not report['paused'] and origin != cell and now-started < .42
|
||||
|
||||
|
||||
def landing_actor_region(state, report, transform, cell, region, transit):
|
||||
"""Derive corridor landings from raw topology, never from actor flags."""
|
||||
if not any(intersects(region, cabin['rect']) for cabin in report['cabins']):
|
||||
return dict(bounds=region, transit=transit)
|
||||
runtime = state['systems']['runtime']
|
||||
footprint = {(stop[0]+dx, stop[1], stop[2])
|
||||
for shaft in elevator_report(state)['shafts'] for stop in shaft['stops']
|
||||
for dx in range(max(int(shaft.get('width', 2)), 1))}
|
||||
walkable = {tuple(c) for c in runtime['world']['walkable_cells']}
|
||||
facilities = codec.indexed(runtime['facilities']['instances'], 'instance_id')
|
||||
owners = {tuple(c): r['entity_id'] for r in runtime['world']['occupancies'] for c in r['cells']}
|
||||
distance = lambda c: (abs(c[0]-cell[0]), c[0])
|
||||
origins = sorted((c for c in footprint if c[1:] == tuple(cell[1:])), key=distance)
|
||||
lane = set()
|
||||
for origin in origins:
|
||||
for direction in (-1, 1):
|
||||
for step in range(1, 9):
|
||||
target = (origin[0]+direction*step, origin[1], origin[2])
|
||||
facility = facilities.get(owners.get(target))
|
||||
if (target in footprint or target not in walkable or
|
||||
(facility and facility['definition_id'] not in ('guest_corridor', 'service_corridor'))):
|
||||
break
|
||||
lane.add(target)
|
||||
lane = sorted(lane, key=distance)
|
||||
if not lane:
|
||||
rect = transform.rect(cell)
|
||||
badges = [b for b in report['landing_badges'] if b['cell'][1:] == list(cell[1:])]
|
||||
anchor = min(badges, key=lambda b: distance(b['cell']))['at'] if badges else [rect[0]-80, rect[1]-16]
|
||||
return dict(bounds=region, transit=False, no_lane=True, badge_at=anchor)
|
||||
reserved = list(report['queue_positions'].values())
|
||||
selected = next((c for c in lane if transform.center(c) not in reserved), lane[0])
|
||||
return dict(bounds=transform.rect(selected), transit=False, center=transform.center(selected))
|
||||
|
||||
|
||||
def compare_actor_geometry(state, report):
|
||||
runtime = state['systems']['runtime']
|
||||
compare_queues(state, report)
|
||||
@@ -1467,6 +1501,9 @@ def compare_actor_geometry(state, report):
|
||||
facilities = codec.indexed(runtime['facilities']['instances'], 'instance_id')
|
||||
staff = codec.indexed(runtime['staff']['staff'], 'staff_id')
|
||||
occupancy = {r['entity_id']: r['cells'] for r in runtime['world']['occupancies']}
|
||||
# Cabin rectangles and badges are independently recomputed before use below.
|
||||
if report['cabins']:
|
||||
compare_cabin_geometry(state, report)
|
||||
counts, expected = {}, []
|
||||
def track_position(key, cell):
|
||||
track = report['actor_tracks'][key]
|
||||
@@ -1489,11 +1526,62 @@ def compare_actor_geometry(state, report):
|
||||
anchors = room_slots(transform.room(cells), p, definition)
|
||||
index = users.index(identifier)
|
||||
return [anchors[index][0], anchors[index][1]+dy] if index < len(anchors) else None
|
||||
people = {'guest/'+r['guest_id']: r for r in runtime['guests']['guests']}
|
||||
people.update({'staff/'+sid: r for sid, r in staff.items()})
|
||||
regions = {}
|
||||
def actor_region(key):
|
||||
if key in regions:
|
||||
return regions[key]
|
||||
person = people[key]
|
||||
cell = person['current_cell']
|
||||
rect = transform.rect(cell)
|
||||
transit = actor_track_transit(report, key, cell)
|
||||
if transit:
|
||||
other = transform.rect(report['actor_tracks'][key]['from'])
|
||||
x, y = min(rect[0], other[0]), min(rect[1], other[1])
|
||||
rect = [x, y, max(rect[0]+rect[2], other[0]+other[2])-x,
|
||||
max(rect[1]+rect[3], other[1]+other[3])-y]
|
||||
result = dict(bounds=rect, transit=transit)
|
||||
fid = ''
|
||||
if key in report['queue_positions']:
|
||||
cx, cy = report['queue_positions'][key]
|
||||
result = dict(bounds=[cx-transform.dim[0]/2, cy-height/2, transform.dim[0], height], transit=False)
|
||||
elif key.startswith('guest/'):
|
||||
target = person['target_facility_id']
|
||||
if person['current_service_id'] and person['guest_id'] in report['rooms'].get(target, {}).get('people', []):
|
||||
fid = target
|
||||
else:
|
||||
sid = person['staff_id']
|
||||
if sid in report['carried_patients']:
|
||||
result = copy.deepcopy(actor_region('staff/'+report['carried_patients'][sid]))
|
||||
result['bounds'][1] -= 12*p
|
||||
if 'center' in result:
|
||||
result['center'][1] -= 12*p
|
||||
elif sid in report['resting_staff']:
|
||||
fid = report['resting_staff'][sid]
|
||||
elif sid in report['treated_patients']:
|
||||
fid = report['treated_patients'][sid]
|
||||
else:
|
||||
target = person['assigned_facility_id']
|
||||
cells = occupancy.get(target, [])
|
||||
workers = report['rooms'].get(target, {}).get('staff', [])
|
||||
if person['state'] in ('WORKING', 'AVAILABLE') and cell in cells and sid in workers:
|
||||
rect = transform.room(cells)
|
||||
columns = max(int(rect[2]/(16*p)), 1)
|
||||
slot = workers.index(sid)
|
||||
if rect[3] >= 40*p and slot < columns:
|
||||
result = dict(bounds=[rect[0]+slot*rect[2]/columns, rect[1], rect[2]/columns, rect[3]], transit=False)
|
||||
if fid and occupancy.get(fid):
|
||||
result = dict(bounds=transform.room(occupancy[fid]), transit=False)
|
||||
if key not in report['queue_positions'] and 'center' not in result and not result.get('no_lane'):
|
||||
result = landing_actor_region(state, report, transform, cell, result['bounds'], result['transit'])
|
||||
regions[key] = result
|
||||
return result
|
||||
for guest in runtime['guests']['guests']:
|
||||
key, cell = 'guest/'+guest['guest_id'], guest['current_cell']
|
||||
if key in report['boarded'] or key in report['queue_hidden'] or cell[2] != report['layer']:
|
||||
continue
|
||||
center = track_position(key, cell)
|
||||
center = actor_region(key).get('center', track_position(key, cell))[:]
|
||||
if key in report['queue_positions']:
|
||||
center = report['queue_positions'][key]
|
||||
elif guest['current_service_id']:
|
||||
@@ -1511,7 +1599,7 @@ def compare_actor_geometry(state, report):
|
||||
key, cell = 'staff/'+sid, member['current_cell']
|
||||
if key in report['boarded'] or key in report['queue_hidden'] or cell[2] != report['layer']:
|
||||
continue
|
||||
center = track_position(key, cell)
|
||||
center = actor_region(key).get('center', track_position(key, cell))[:]
|
||||
special = True
|
||||
if key in report['queue_positions']:
|
||||
special = False
|
||||
@@ -1521,6 +1609,7 @@ def compare_actor_geometry(state, report):
|
||||
if carrier:
|
||||
center = track_position('staff/'+carrier['staff_id'], carrier['current_cell'])
|
||||
center[1] -= 12*p
|
||||
center = actor_region(key).get('center', center)[:]
|
||||
elif sid in report['resting_staff']:
|
||||
center = slot_position(report['resting_staff'][sid], sid, 'staff_waiting_room', center, -height*.5)
|
||||
elif sid in report['treated_patients']:
|
||||
@@ -1555,55 +1644,16 @@ def compare_actor_geometry(state, report):
|
||||
carried = bool(staff.get(key.removeprefix('staff/'), {}).get('carried_inventory_id')) if is_staff else False
|
||||
expected.append((key, center, is_staff, False, carried, True))
|
||||
cabin_bounds[key] = cabin['rect']
|
||||
people = {'guest/'+r['guest_id']: r for r in runtime['guests']['guests']}
|
||||
people.update({'staff/'+sid: r for sid, r in staff.items()})
|
||||
def tracked_bounds(key, cell):
|
||||
track = report['actor_tracks'][key]
|
||||
transit = actor_track_transit(report, key, cell)
|
||||
rect = transform.rect(cell)
|
||||
if transit:
|
||||
other = transform.rect(track['from'])
|
||||
x, y = min(rect[0], other[0]), min(rect[1], other[1])
|
||||
rect = [x, y, max(rect[0]+rect[2], other[0]+other[2])-x,
|
||||
max(rect[1]+rect[3], other[1]+other[3])-y]
|
||||
return rect, transit
|
||||
members = []
|
||||
members, stranded = [], []
|
||||
for key, center, is_staff, receiving, carrying, riding in expected:
|
||||
person = people[key]
|
||||
cell = person['current_cell']
|
||||
track = report['actor_tracks'].get(key, {})
|
||||
region, transit = (cabin_bounds[key], False) if riding else tracked_bounds(key, cell)
|
||||
fid = ''
|
||||
if not riding:
|
||||
if key in report['queue_positions']:
|
||||
cx, cy = report['queue_positions'][key]
|
||||
region, transit = [cx-transform.dim[0]/2, cy-height/2, transform.dim[0], height], False
|
||||
elif not is_staff:
|
||||
target = person['target_facility_id']
|
||||
if receiving and target in facilities and key.split('/', 1)[1] in report['rooms'].get(target, {}).get('people', []):
|
||||
fid = target
|
||||
else:
|
||||
sid = person['staff_id']
|
||||
if sid in report['carried_patients']:
|
||||
carrier = staff[report['carried_patients'][sid]]
|
||||
region, transit = tracked_bounds('staff/'+carrier['staff_id'], carrier['current_cell'])
|
||||
region[1] -= 12*p
|
||||
elif sid in report['resting_staff']:
|
||||
fid = report['resting_staff'][sid]
|
||||
elif sid in report['treated_patients']:
|
||||
fid = report['treated_patients'][sid]
|
||||
else:
|
||||
target = person['assigned_facility_id']
|
||||
cells = occupancy.get(target, [])
|
||||
workers = report['rooms'].get(target, {}).get('staff', [])
|
||||
if person['state'] in ('WORKING', 'AVAILABLE') and target in facilities and cell in cells and sid in workers:
|
||||
rect = transform.room(cells)
|
||||
columns = max(int(rect[2]/(16*p)), 1)
|
||||
slot = workers.index(sid)
|
||||
if rect[3] >= 40*p and slot < columns:
|
||||
region, transit = [rect[0]+slot*rect[2]/columns, rect[1], rect[2]/columns, rect[3]], False
|
||||
if fid and occupancy.get(fid):
|
||||
region, transit = transform.room(occupancy[fid]), False
|
||||
relocation = {} if riding else actor_region(key)
|
||||
if riding:
|
||||
region, transit = cabin_bounds[key], False
|
||||
else:
|
||||
region, transit = relocation['bounds'], relocation['transit']
|
||||
scale = .5 if riding else .75
|
||||
scale = max(math.floor(p*scale), 1) if p >= 2 else p*scale
|
||||
at = [center[0]-8*scale, center[1]+height*.5-3*p-17*scale]
|
||||
@@ -1650,13 +1700,23 @@ def compare_actor_geometry(state, report):
|
||||
frame=frame, variant=variant, flip=track.get('direction', 1) < 0,
|
||||
staff=is_staff, state=states.index(person['state']), receiving=receiving,
|
||||
carrying=carrying, riding=riding)
|
||||
members.append(dict(row=row, bounds=[region[0]+p, region[1]+p, region[2]-2*p, region[3]-2*p], transit=transit))
|
||||
if relocation.get('no_lane'):
|
||||
aggregate = next((a for a in stranded if a['at'] == relocation['badge_at']), None)
|
||||
if aggregate is None:
|
||||
aggregate = dict(members=[], drawn_keys=[], at=relocation['badge_at'], text='')
|
||||
stranded.append(aggregate)
|
||||
aggregate['members'].append(dict(key=key, id=key.split('/', 1)[1], state=row['state'], cell=cell, mode=mode))
|
||||
aggregate['text'] = '+'+str(len(aggregate['members']))
|
||||
else:
|
||||
members.append(dict(row=row, bounds=[region[0]+p, region[1]+p, region[2]-2*p, region[3]-2*p], transit=transit))
|
||||
fitted, aggregations = fitted_actor_layout(members, p, height)
|
||||
aggregations = stranded + aggregations
|
||||
close(report.get('actor_aggregations'), aggregations, 'actor aggregation/no-fit')
|
||||
require([r['key'] for r in report['actor_drawings']] == [k for k in floor_keys if k in fitted], 'actor drawing coverage/order')
|
||||
actual = list(report['actor_drawings']) + [r for c in report['cabins'] for r in c['passengers']]
|
||||
require(len(actual) == len(fitted) and {r['key'] for r in actual} == set(fitted), 'missing or duplicate actor')
|
||||
for row in actual:
|
||||
require('region' not in row and 'boarded' not in row, 'unsupported actor projection flags')
|
||||
for field, value in fitted[row['key']].items():
|
||||
close(row[field], value, 'actor fitted '+field)
|
||||
exemptions = {m['row']['key'] for m in members if m['transit']}
|
||||
|
||||
Reference in New Issue
Block a user