The Mind-Lattice of Halvory Steppe
The war-mages who ride with the Halvory Steppe outriders carry their spells in a Mind-Lattice, a crystal lens bound behind the eyes. It holds a fixed number of prepared spells. When it is full, a new spell pushes an old one out. The Lattice-Wrights' Guild offers a bounty for a faithful model of the lattice, so that young mages can rehearse before they ride.
Write the class SpellMind. Its constructor takes capacity, a non-negative integer: the most spells the lattice can hold at once. The lattice starts empty.
Each held spell has: - a name (a string, unique within the lattice), - a number of charges (an integer), - a potency (an integer), - a sealed flag, which starts false, - a recency.
A spell is *touched* when it is prepared (including re-prepared) or cast. Its recency is the moment of its most recent touch. Sealing, unsealing and listing never touch anything.
### Methods
`prepare(name, charges, potency)` takes charges (an integer ≥ 1) and potency (an integer). It returns a string or null. - Already held: if name is already held, its charges and potency are replaced by the new values. It keeps its sealed flag, it is touched, and the method returns null. Nothing is forgotten, even when the lattice is full. - Room to spare: otherwise, if fewer than capacity spells are held, the spell is added (unsealed and touched) and the method returns null. - Full, with an unsealed spell: otherwise, if at least one held spell is unsealed, exactly one unsealed spell is forgotten. The one forgotten has the lowest potency; among equal potencies, it is the one touched least recently. The new spell is then added (unsealed and touched), and the method returns the forgotten spell's name. The newcomer is always admitted this way, even if its potency is lower than every held spell's. - Full, all sealed: otherwise (every held spell is sealed, or capacity is 0), the new spell is refused. Nothing changes, and the method returns name itself.
`cast(name)` returns an integer. - If name is not held, it returns -1 and nothing changes. - Otherwise the spell loses one charge, is touched, and the method returns its remaining charges. - If that leaves 0 charges, the spell is forgotten immediately, sealed or not.
`seal(name)` returns a boolean. If name is held, the spell becomes sealed and the method returns true. Otherwise it returns false. Sealed spells are never chosen to be forgotten by prepare.
`unseal(name)` returns a boolean. If name is held, the spell becomes unsealed and the method returns true. Otherwise it returns false.
`held()` returns a list of the names of all held spells, ordered from most recently touched to least recently touched. It returns an empty list if none are held.
examples
- case 1
capacity 2; prepare Hex (2 charges, potency 3), prepare Mire (2 charges, potency 3), cast Hex, prepare Spark (1 charge, potency 9)cast Hex returns 1; prepare Spark returns "Mire". The potencies are tied, and Mire was touched longer ago than Hex. - case 2
capacity 2; prepare Bolt (1 charge, potency 9), seal Bolt, prepare Flare (2 charges, potency 6), seal Flare, prepare Glimmer (1 charge, potency 10)prepare Glimmer returns "Glimmer". Both held spells are sealed, so Glimmer is refused and held() is still ["Flare", "Bolt"]. - case 3
capacity 2; prepare Bolt (1 charge, potency 9), seal Bolt, cast Bolt, cast BoltThe first cast returns 0, and Bolt is forgotten despite its seal. The second cast returns -1.
- reward
- 530 XP
- signature
SpellMind
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- lowest potency is forgotten first
- equal potency falls to least recently touched
- sealed spells are spared and full seals refuse
- spent charges forget even a sealed spell
- capacity zero refuses everything
- re-preparing keeps the seal and resets charges
- re-preparing refreshes recency and potency
- a weak newcomer still displaces at capacity one