‹ back to the board

Wednesday, September 23

Mastermulti-constraint & composite logic

The Wallwright's Tally Stone

The wallwright of bitwick keeps the town wall in repair, and every cart that arrives brings a delivery slip scrawled by whoever loaded it. The guild will only carve a measure into the tally stone in one fixed form, so the slips must be rewritten before they are carved.

Measures use four units:

  • 1 league = 4 rods
  • 1 rod = 6 spans
  • 1 span = 5 nails

Write canonicalTally(slip), which takes a string and returns a string.

Reading the slip. The slip's tokens are separated by one or more whitespace characters, and there may be leading or trailing whitespace. The slip may be empty or contain only whitespace. Otherwise it is made of:

  • An optional first token minus. If present, it negates the *entire* total of everything after it. It can appear only as the first token, and at most once.
  • Then zero or more terms. Each term is optionally preceded by the token less, which negates *only that one term*. The term itself is a count token followed by a unit token. A count is an optional - followed by one or more decimal digits. A unit token is one of league, leagues, rod, rods, span, spans, nail, nails — singular and plural mean the same thing in the input, whatever the count is.

The slip's value, in nails, is the sum of every term's count times its unit's size in nails, with a term's sign flipped if less precedes it, and the whole sum negated if the slip begins with minus. You may assume the slip is well formed as described.

Carving the stone. Return the canonical rendering of that value:

  • If the value is zero, return exactly "0 nails".
  • Otherwise, take the absolute value and break it into leagues, rods, spans and nails so that the count of nails is under 5, the count of spans is under 6, and the count of rods is under 4.
  • Render each unit whose count is not zero, largest unit first, as the count, a single space, and the unit name — singular when the count is exactly 1, plural otherwise. Units with a count of zero are not rendered at all.
  • Join those with single spaces. If the value is negative, put the token minus and a single space before the whole thing.

There is no other whitespace in the returned string.

  • format round-tripping
  • Master

examples

  1. case 1slip of "3 rods 14 spans""1 league 1 rod 2 spans" — 3 rods and 14 spans is 160 nails, which is 1 league, 1 rod and 2 spans
  2. case 2slip of "1 league less 1 nail""3 rods 5 spans 4 nails" — 119 nails, and the zero league count is not rendered
  3. case 3slip of "minus 1 rod -2 spans""minus 4 spans" — the terms give 30 - 10 = 20 nails, and the leading minus negates the whole of it
  4. case 4slip of "1 rod less 6 spans""0 nails" — the terms cancel exactly
reward
540 XP
signature
canonicalTally
not yet run

TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.

loading the editor…
  • mixed slip carries into leagues
  • empty slip
  • terms cancel to nothing
  • leading minus meets a negative count
  • less drops a zero league count
  • less with a negative count adds
  • plural input singular output
  • ragged whitespace
  • exact league
  • leading minus over a negative total
  • minus before a zero count
  • long slip skips empty spans
  • canonical slip re-reads unchanged
The Wallwright's Tally Stone · bitwick