‹ back to the board

today · Wednesday, October 28

Mastermulti-constraint & composite logic

The Philter-Scripts of Thornmere Abbey

Each autumn the barrow-wights walk the moor below Thornmere Abbey, and the Sisters hold them back with warding philters. Every philter is written as a terse philter-script naming the essences to be ground into it. A mis-copied script ruins a batch, so the Abbess pays for every script to be checked and reduced to a single canonical tally before the mortars are filled.

Write tallyEssences(script). It takes one string, script, and returns a string.

What makes a script valid. A valid script follows these rules exactly. Any other character, including spaces, makes it invalid.

  • A script is one or more parts separated by single + characters. There must be a part on both sides of every +, so the script cannot be empty.
  • A part is an optional coefficient followed by one or more units.
  • A unit is either an essence or a group. Either may be followed by an optional multiplier.
  • An essence is one uppercase letter A-Z followed by zero or more lowercase letters a-z. Its name is that whole run of letters. SaltBone is two essences, Salt and Bone.
  • A group is ( followed by one or more units and then ), or [ followed by one or more units and then ]. Groups may nest. Every bracket must be closed by the matching kind, in properly nested order. An empty group such as () is invalid.
  • A coefficient or multiplier is a run of one or more digits 0-9 whose first digit is not 0, read as a positive base-10 integer. 0, 01 and 007 are never valid numbers.
  • A unit with no multiplier counts once. A part with no coefficient counts once.

What it is worth. Each essence occurrence contributes the product of these numbers:

  • its own multiplier,
  • the multiplier of every group enclosing it,
  • the coefficient of its part.

The tally of an essence is the sum of its contributions across the whole script, over all parts.

What to return.

  • If the script is invalid, return exactly "INVALID".
  • Otherwise, return every essence that appears, in ascending order of name, concatenated with no separators. Each name is followed by its total tally written in base 10. The tally is omitted when it is exactly 1.
  • Names are compared character by character by character code, so a name sorts before any longer name that begins with it. For example, E sorts before Ember.
  • tokenizing and evaluating
  • Master

examples

  1. case 1script of "2(SaltBone)3+Mist""Bone6MistSalt6" (Salt and Bone are 1 x 3 x 2 = 6 each; Mist counts once, so no number)
  2. case 2script of "[Ash(EmberMist2)2]3""Ash3Ember6Mist12"
  3. case 3script of "EmberE2""E2Ember" (E sorts before Ember, the longer name it begins)
  4. case 4script of "(Ash+Mist)""INVALID" (a + may not appear inside an open bracket)
reward
540 XP
signature
tallyEssences
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…
  • simple essences sorted
  • coefficient and group multiplier
  • nested mixed brackets
  • merge across parts
  • mismatched brackets
  • empty group
  • leading zero multiplier
  • zero multiplier
  • zero coefficient
  • trailing plus
  • empty script
  • coefficient alone
  • empty first part
  • digit after opening bracket
  • lowercase start
  • single letter essence
  • explicit multiplier of one
  • unclosed bracket
  • stray closing bracket
  • plus inside group
  • prefix name ordering
  • multi-digit numbers
  • space is invalid
  • repeated essence in one part
  • double plus
  • deep nesting with coefficient
The Philter-Scripts of Thornmere Abbey · bitwick