The Knot-Cords of the Drennick Outriders
The Drennick Outriders ride the long patrols beyond Bitwick and send word home on knotted cords. At the Outrider post, scribes copy each cord into a shorthand, but they copy carelessly. They split one run of knots across several groups, they write needless counts of 1, and sometimes they botch the notation entirely. The Cord-Warden of the post pays a standing bounty for every cord rewritten in the one canonical shorthand, and for every botched cord caught.
The shorthand. A cord is a string of printable ASCII characters. It is read left to right as a sequence of *groups*. Each group is an optional *count* followed by exactly one *symbol*:
- A count is all the consecutive digits
0-9at the start of a group, read as a decimal number. It must not begin with0. A group with no digits has count 1. - A symbol is one of two things. It may be a single character that is neither a digit nor a backslash; spaces and punctuation count as symbols. Or it may be a backslash followed by a digit or by a second backslash, and it then stands for that digit or for a backslash.
- A group stands for its symbol's character repeated *count* times. The message is the characters of all groups, concatenated in order.
A cord is malformed if any of the following is true:
- a count begins with
0; - digits run to the end of the cord with no symbol after them;
- a backslash is the last character;
- a backslash is followed by anything other than a digit or a backslash.
The canonical form. Split the message into maximal runs of identical characters. Write each run, in order, as one group:
- First its length, as a decimal number with no leading zeros. Omit the length entirely when it is 1.
- Then its character. Escape the character with a backslash if it is a digit or a backslash. Otherwise write it plainly.
Write retieCord(cord). Given cord (a string), it returns the canonical form of that cord as a string. If the cord is malformed, it returns null in TypeScript and None in Python. The empty cord is well-formed, and its canonical form is the empty string.
Each count is at most 1,000,000,000 and a cord has at most 1,000 characters. A message may therefore be far too long to write out in full.
examples
- case 1
the cord `2a3ab``5ab`: the two groups of a are one run of five - case 2
the cord `\3\32\3``4\3`: an escaped 3, another escaped 3, two more escaped 3s, so four 3s in one run - case 3
the cord `2 a 3 ``2 a4 `: spaces are symbols, and the single space joins the three after it - case 4
the cord `a0b`null (None): the count before b begins with 0
- reward
- 540 XP
- signature
retieCord
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- merges-adjacent-groups
- count-of-one-dropped
- empty-cord
- single-symbol
- run-across-plain-groups
- multi-digit-counts
- zero-inside-count
- escaped-digits-merge
- escaped-ones-collapse
- escaped-backslashes
- spaces-are-symbols
- huge-counts
- leading-zero-rejected
- zero-mid-cord-rejected
- trailing-count
- trailing-backslash
- bad-escape
- escape-then-dangling-count