The Apothecary's Rune-Wands
The apothecary of bitwick will not shelve a rune-wand until the counting-stone has read it. Each wand carries a single line of runes, read left to right; a line that breaks the craft's rules is faulty and the wand is worth nothing.
You are given line, a string. Split it on whitespace to get the runes (leading, trailing and repeated whitespace are ignored; a line with no runes at all is possible). Write wandValue(line), which returns the wand's value as an integer, or null in TypeScript / None in Python if the line is faulty.
## The runes
The stone keeps a stack of integers, empty at the start.
- A number is an optional
-followed by one or more digits (7,-3,007). It pushes its value. +,-,*each pop two values. Calling the deeper oneaand the upper oneb, they pusha + b,a - b,a * brespectively.duppushes a copy of the top value.swapexchanges the top two values.dropremoves the top value.reppops one valuen, then runs the block that immediately follows it exactlyntimes, one run after another. Ifnis zero or negative the block is not run at all. Blocks may contain furtherreps.- A block is the rune
[, then zero or more runes, then its matching].
## Faulty lines
The shape of the line is judged over every rune in it, whether or not that rune is ever reached. A line is faulty if any of these hold:
- some rune is not a number, not one of
+ - * dup swap drop rep, and not[or]; - a
[appears anywhere other than immediately after arep; - a
repis not immediately followed by a[; - the brackets are not balanced and properly nested.
Otherwise the line is run. It is also faulty if:
- any rune needs more values than the stack currently holds (including
repneeding its count); - after every rune has been run, the stack does not hold exactly one value.
When the line is not faulty, the single value left on the stack is the result.
examples
- case 1
line of "2 3 + 4 *"20 - case 2
line of "1 5 rep [ 2 * ]"32 — the count 5 is popped, then the block doubles the 1 five times - case 3
line of "3 rep [ 2 2 + ]"faulty (null / None) — three values are left on the stack - case 4
line of "0 rep [ nope ] 5"faulty (null / None) — the block never runs, but `nope` is not a rune
- reward
- 540 XP
- signature
wandValue
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- plain arithmetic
- nested repeats
- count taken from the stack
- zero count skips the block
- negative count skips the block
- empty block
- bad rune inside a skipped block
- stack underflow
- two values left over
- no runes at all
- bracket without a repeat
- unclosed block
- repeat without a block
- stray closing bracket
- repeat with nothing to count
- negative literal and subtraction
- shuffling runes
- ragged whitespace
- plus-signed number is not a rune
- padded digits