‹ back to the board

Monday, October 26

Mastermulti-constraint & composite logic

The Knot-Charms of Kethra Steppe

On the Kethra Steppe, the wardens of the horse-clans tie their protections as knot-charms. Each charm is a named cord, and smaller named cords may hang from it, each of which may carry cords of its own. Copies passed from rider to rider come back written in many different ways. The Wardens' Lodge has posted a bounty for a scribe who can write any charm in its one true form. Two charms are the same charm exactly when their true forms match, and a botched copy must be caught before anyone ties it.

Write trueKnot(cord). It takes a string cord and returns a string: the true form of the charm, or "" (the empty string) if cord is malformed.

Notation. The input is well-formed only if it matches all of these rules exactly: - A name is one or more lowercase letters a–z. - A cord is a name, optionally followed immediately by (, then zero or more entries separated by single commas, then ). So a() is allowed, but a(,b), a(b,) and a(b are not. - An entry is a cord, optionally preceded by a count. A count is one or more digits 0–9 followed by *. It is read as a decimal number, and leading zeros are allowed, so 007* means 7. An entry with no count has count 1. - The whole input must be exactly one cord with no count in front. No other characters may appear anywhere, including spaces.

True form. The true form of a cord named N is defined from the true forms of the cords hanging from it: 1. An entry with count k contributes k copies of its cord's true form. Copies whose true forms are equal are pooled, and their counts are added together. A true form whose pooled total is 0 is dropped. 2. If nothing remains, the true form is just N, with no parentheses. 3. Otherwise, the true form is N, then (, then each remaining distinct true form, separated by ,, then ). - Write each one as t*F if its total t is 2 or more, and as plain F if its total is 1. - List them in ascending order of F, the form without its count prefix. Compare strings character by character using ASCII character codes, and if one string is a prefix of the other, the shorter comes first. - Under this ordering, ( < ) < * < , < digits < lowercase letters.

The input is at most a few hundred characters of printable ASCII. No pooled total exceeds 1,000,000.

  • recursive-descent parsing
  • Master

examples

  1. case 1cord of "knot(a(0*x),a,b())""knot(2*a,b)": a(0*x) loses its only child and becomes plain a, so it pools with the bare a, and b() becomes b
  2. case 2cord of "root(a(c,b),a(b,c))""root(2*a(b,c))": both children have the true form a(b,c), so they pool into a total of 2
  3. case 3cord of "k(ab,a(b),a)""k(a,a(b),ab)": a is a prefix of a(b), so it comes first, and ( sorts before the letter b
  4. case 4cord of "ward(ash,)""": a trailing comma makes the charm malformed
reward
540 XP
signature
trueKnot
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…
  • sorts_children
  • pools_counts
  • pools_equivalent_subtrees
  • zero_child_collapses_and_pools
  • paren_sorts_before_letters
  • digits_sort_before_letters
  • deep_nesting
  • mixed_forms_pool
  • leading_zero_counts
  • all_children_zero
  • single_name
  • empty_parens
  • empty_input
  • trailing_comma
  • lone_comma
  • count_on_top_level
  • uppercase_name
  • unclosed
  • extra_close
  • count_without_star
  • star_without_count
  • count_without_cord
  • second_group
  • space_rejected
The Knot-Charms of Kethra Steppe · bitwick