‹ back to the board

Sunday, September 20

Mastermulti-constraint & composite logic

The Quarry Clerk's Tally-Slates

The quarry clerk of bitwick kept every day's haul on a slate, written in the old chisel notation. The clerk is gone, the notation went with her, and the guild wants the slates read back — with the cracked ones flagged rather than guessed at.

The argument slate is a string. Return the integer the slate records, or the empty value (null in TypeScript, None in Python) if the slate is not a well-formed carving.

Cutting the slate into marks

  • A run of one or more digits 0-9 is a *count*, read as a decimal number. Leading zeros are allowed, so 007 is seven.
  • Each of +, -, *, >, !, (, ) is a single mark.
  • A space separates marks and carries no other meaning.
  • Any other character makes the slate malformed.

What counts as well-formed

  • A *stone* is either a count, or a ( ) pair enclosing a whole carving, in either case followed by zero or more ! marks.
  • A *carving* is a single stone, or two or more stones separated by the binary marks +, -, *, >.
  • The slate is well-formed exactly when its marks form one whole carving with nothing left over.
  • Because a space is a separator, 1 2 is two counts standing side by side, which is malformed — it is not the count 12.

What the marks mean, in grouping order, loosest first:

1. + — the sum of its two values; groups left to right. 2. - — the difference of its two values; groups right to left. 3. * — the product of its two values; groups left to right. 4. > — the larger of its two values; groups left to right. 5. ! — written after a stone; negates that stone's value, and may be repeated.

Parentheses override all of the above. Every value is an integer, and the returned value is an integer.

  • recursive-descent parsing
  • Master

examples

  1. case 1slate = "10 - 2 + 3 - 4 - 5"12 — the loosest mark splits it into 10 - 2 and 3 - 4 - 5; the right-leaning difference reads the second as 3 - (4 - 5) = 4, so 8 + 4
  2. case 2slate = "2 > 3!"2 — the strike falls on the 3 alone, so this is the larger of 2 and -3
  3. case 3slate = "(2 > 3)!"-3 — here the strike falls on the bracketed carving, whose value is 3
  4. case 4slate = "1 2"null in TypeScript, None in Python — a space breaks a count, so this is two counts side by side
reward
540 XP
signature
readSlate
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…
  • sum splits loosest, difference leans right
  • difference alone leans right
  • strike falls on a single stone
  • brackets take the strike
  • product binds tighter than difference
  • larger binds tighter than product
  • all four binary marks unspaced
  • difference right-leaning over a product
  • nested carving with a trailing strike
  • struck brackets inside a product
  • strikes stack
  • leading zeros on a lone count
  • blank slate
  • space breaks a count
  • unclosed bracket
  • empty brackets
  • strike with no stone before it
  • no mark stands before a count
  • dangling binary mark
  • foreign character
  • leftover bracket at the end
The Quarry Clerk's Tally-Slates · bitwick