traceRoomAmong function
The room around seed among every contributor source holds, tracing
only those near its face (spec 10 D7). The result is, bit for bit,
traceRoom(seed, every input) (LZ1):
- Growth. Trace among
placedIn(B),B = seed ⊕ r, fromr =kGrowthStart. SeedInWall is final: the wall holding the seed touchesB. Unbounded: doublerand repeat untilBcontainsU(PlaceSource.bounds); then Unbounded is final. With nothing placed at all, Unbounded at once. - Certificate. On
Traced(F),C = placedIn(box(F) ⊕ m),m =kCertificateMargin. WhileCholds a contributor not yet traced, add it and trace again. The face can only shrink or gain holes, so one round always suffices; the loop's exit is the certificate itself. - Canonical trace. The trace among exactly
C: a function ofCand the seed only, whatever growth rounds led there (D16's no-drift proof needs this). When the last trace was already among exactlyC, it is that trace: the same inputs give the same bits.
Why exact: every contributor outside C is disjoint from the closed
face grown by m, and so changes nothing inside it.
A seed with a non-finite coordinate is Unbounded: no box around it
ever contains U.
Implementation
TraceResult traceRoomAmong(Vector2 seed, PlaceSource source) {
final u = source.bounds;
if (u == null || !seed.x.isFinite || !seed.y.isFinite) {
return const Unbounded();
}
List<RoomInput> inputsOf(Iterable<Handle> hs) => [
for (final h in hs)
if (source.inputOf(h) case final input?) input,
];
// 1. Growth.
var r = kGrowthStart;
List<Handle> traced;
Traced face;
while (true) {
final b = Aabb2.raw(seed.x - r, seed.y - r, seed.x + r, seed.y + r);
traced = source.placedIn(b);
final result = traceRoom(seed, inputsOf(traced));
if (result is Traced) {
face = result;
break;
}
if (result is SeedInWall || _holds(b, u)) return result;
r *= 2;
}
// 2. The certificate.
Aabb2 grown(Traced f) =>
Aabb2.fromPoints(f.ring).expandedBy(kCertificateMargin);
final set = {...traced};
var c = source.placedIn(grown(face));
while (!c.every(set.contains)) {
set.addAll(c);
traced = [...set]..sort((a, b) => a.value.compareTo(b.value));
final result = traceRoom(seed, inputsOf(traced));
// Unreachable (D7: more inputs only shrink the face, and the wall
// holding the seed would have touched B), but never a wrong answer.
if (result is! Traced) return result;
face = result;
c = source.placedIn(grown(face));
}
// 3. The canonical trace, among exactly C.
if (_sameHandles(traced, c)) return face;
return traceRoom(seed, inputsOf(c));
}