The Weaver's Warp Card
The mill above bitwick stores every pattern on a punched warp card, and the cards that come back from the villages are written any old way. The weaver wants each one rewritten in the mill's own hand.
card is a string. Read it left to right as a sequence of blocks. A block is an optional count — one or more decimal digits, leading zeros allowed — followed by a unit. A unit is either a single lowercase letter, or one or more lowercase letters enclosed in square brackets. A block with no count has a count of 1. A block contributes its unit's letters repeated *count* times; a count of 0 contributes nothing. The card's thread is the contribution of every block, joined in order. An empty card has an empty thread.
A card is malformed if it does not split exactly into such blocks. That includes: any character other than a–z, 0–9, [, ]; a run of digits not immediately followed by a unit; a [ with no later ]; a ] with no open [; an empty pair of brackets; and anything other than lowercase letters between brackets.
Write canonicalCard(card). If the card is malformed, return the null value of your language (null in TypeScript, None in Python). Otherwise return a string: the mill's canonical writing of the thread, built like this.
- Cut the thread into maximal runs of one repeated letter.
- Cut each run of length
Linto pieces: ifLis 9 or less it is a single piece of lengthL; otherwise take pieces of 9 from the left until 9 or fewer letters remain, and that remainder is the last piece. - Write a piece of length 1 or 2 as that many copies of the letter. Write a piece of length 3 to 9 as the single digit, then the letter.
- Concatenate the pieces of every run, in order.
Every count in card has value at most 999, and the thread is at most a few thousand letters.
examples
- case 1
card of "aa0ba""3a" — the zero count drops the b, so the a's on either side form one run of three - case 2
card of "12a""9a3a" — a run of twelve is cut into a piece of nine and a piece of three - case 3
card of "2[ab]bb""aba3b" — the thread is ababbb, whose runs are a, b, a, and bbb - case 4
card of "a[]b"null in TypeScript, None in Python — empty brackets are malformed
- reward
- 540 XP
- signature
canonicalCard
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- plain thread needs no counts
- bracket group repeats
- zero count joins its neighbours
- run of twelve splits after nine
- run of ten leaves a single letter
- nineteen makes two nines and a single
- ninety-nine is eleven nines
- leading zeros in a count
- runs merge across blocks
- repeated bracket body forms one run
- empty card
- everything cancels
- unmatched open bracket
- nested bracket
- digit inside brackets
- count with no unit
- empty brackets
- stray close bracket
- capital is not thread