The Surveyor's Crooked Field Notes
Pinned by the door, in a surveyor's hand.
The terraces above bitwick were levelled last autumn, one line of the notebook per measurement, each line saying how high one stone sits relative to another. Rain got into the book: some lines can no longer be read as measurements at all, and some disagree with lines written earlier. The stonewright needs the differences that still hold.
Write resolveLevels(notes, queries). notes is a list of strings; queries is a list of two-element lists of strings. Return a list with one entry per query, in order — each entry an integer or null (None in Python).
Well-formed notes. Split a note on single space characters (so "a b" yields three pieces, the middle one empty). The note is well-formed only if this yields exactly five pieces t0 t1 t2 t3 t4 with:
t0andt4non-empty — the two stone names, compared exactly;t1equal tois;- and either
t2a run of one or more digits0–9(leading zeros allowed) together witht3equal toaboveorbelow, ort2equal toleveltogether witht3equal towith.
A well-formed note asserts, writing h for height in hands and n for the value of t2:
A is n above B: h(A) = h(B) + nA is n below B: h(A) = h(B) − nA is level with B: h(A) = h(B)
Accepting. Work through notes in order. Ignore any note that is not well-formed. Ignore any well-formed note whose assertion contradicts the assertions already accepted; a note that merely restates something already forced is accepted. An ignored note has no effect whatsoever.
Answering. For a query [A, B], the entry is h(A) − h(B) when the accepted notes force that value, and null when they do not. If A and B are the same string, the entry is 0, even when that name appears in no accepted note.
examples
- case 1
notes of ["forge is 3 above well", "well is level with dock"], queries of [["forge", "dock"], ["forge", "kiln"]][3, null] — the forge is fixed 3 hands above the dock; nothing ties the kiln to anything - case 2
notes of ["a is 5 above b", "b is 5 above a", "b is 1 above c"], queries of [["a", "c"]][6] — the second note contradicts the first and is struck out, but the third is still accepted, so a sits 5 + 1 above c - case 3
notes of ["a is 3 under b", "a is 3 above b", "a is 3 above b extra"], queries of [["a", "b"]][null] — the first uses an unknown word, the second splits into six pieces because of the double space, the third into six pieces as well; nothing is accepted - case 4
notes of ["tower is 4 above tower"], queries of [["tower", "tower"], ["tower", "cellar"]][0, null] — the note contradicts itself and is dropped, yet a stone is always level with itself
- reward
- 510 XP
- signature
resolveLevels
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- chain of terraces
- a later note contradicts, the earlier one survives
- smudged lines are struck out
- empty notebook
- a stone measured against itself
- a bridge that disagrees with the joined frames