The Ward-Carver of the North Gate
Over the north gate of bitwick, the ward-carver recuts inscriptions before they are set into stone. A ward only holds if every operation in it is bracketed exactly once. Apprentices bring her inscriptions written flat, with the brackets left out, and she must work out the grouping and cut it herself. Sometimes what an apprentice brings is not an inscription at all, and then the stone is left blank.
expr is a string containing no whitespace. Return a string: the fully bracketed recut of expr, or the empty string "" if expr is not a well-formed inscription.
An inscription is one of:
- a numeral: one or more of the digits
0-9(leading zeros are allowed, and are kept as written) (followed by an inscription followed by)- an operator applied to inscriptions.
The operators, loosest-binding first:
1. = — binary, non-associative: at most one = may stand outside brackets in any one inscription, so a=b=c is not well-formed while (a=b)=c is 2. + and - — binary, left-associative 3. * and / — binary, left-associative 4. ^ — binary, right-associative 5. - — prefix, and may be stacked 6. ! — postfix, and may be stacked
Prefix - binds looser than ^, so -a^b groups as -(a^b). The operand to the right of ^ is read at the prefix level, so a^-b is well-formed and groups as a^(-b); the operand to the left of ^ is read at the postfix level, so a prefix - standing there always applies to the whole power.
The recut:
- a numeral recuts to itself
- a binary application recuts to
(+ recut left operand + the operator character + recut right operand +) - a prefix
-application recuts to(-+ recut operand +) - a postfix
!application recuts to(+ recut operand +!)
The result contains no spaces and no brackets other than those, so brackets in expr that only restate a grouping already forced by the rules do not appear in the result.
Anything that is not an inscription — including an inscription followed by any leftover characters, and including the empty string — is not well-formed.
examples
- case 1
expr = "-2^3!""(-(2^(3!)))" — the postfix binds tightest, the power next, and the prefix minus takes the whole power - case 2
expr = "2^-3*4""((2^(-3))*4)" - case 3
expr = "(((7)))""7" — no operator was applied, so no bracket is cut - case 4
expr = "1=2=3""" — a second bare `=` is not well-formed
- reward
- 540 XP
- signature
carveWard
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- star binds tighter than plus
- prefix minus takes the whole power
- power is right associative
- minus on the right of a power
- subtraction is left associative
- the seal cannot be chained
- a bracketed seal may be sealed again
- seal is looser than addition
- redundant brackets vanish
- stacked prefix and postfix
- postfix after a bracketed group
- leading zeros are kept
- blank stone
- leftover rubble
- dangling operator
- empty brackets