The Spirit-Jars of Hollenbrask Bazaar
Commission of the Binders' Lodge, Hollenbrask Bazaar
The spirit-binder Maudrey Venn walks the caravan roads with a rack of warded jars, each holding one bound spirit. The rack has room for only so many. When a new spirit must go in and the rack is full, one spirit is released back into the wild to make room. Some jars carry a seal, and a sealed spirit is never released. The Lodge wants the rack's rules made exact. Build the class SpiritRack.
Construction. The rack is created with one argument, capacity, a non-negative integer: the most spirits it can hold at once.
State. Each held spirit has a name (a non-empty string of lowercase letters), a power (a non-negative integer), a use count, a time of last use, and a sealed flag.
A use is either a successful bind of that spirit or a summon of it while it is held. Each use adds 1 to the spirit's use count and makes it the most recently used spirit.
Methods
bind(name, power)returns a boolean.- If
nameis already held, its power becomespower. This counts as a use. Its sealed flag is unchanged and no spirit is released. Returntrue. - Otherwise, if fewer than
capacityspirits are held, add the spirit with use count 1, as the most recently used, unsealed. Returntrue. - Otherwise the rack is full. Among the unsealed held spirits, choose the one with the lowest use count. If several are tied, choose the one whose last use is earliest. Release that spirit, then add the new one as described above, and return
true. If no held spirit is unsealed (this includes a capacity of 0), nothing changes and the method returnsfalse. summon(name)returns the spirit's power if it is held, and this counts as a use. If it is not held, return-1and change nothing.seal(name): if the spirit is held, mark it sealed and returntrue. Otherwise returnfalse. This is not a use.unseal(name): if the spirit is held, clear its sealed mark and returntrue. Otherwise returnfalse. This is not a use.held()returns the names of all held spirits as a list of strings, sorted in ascending alphabetical order.
A released spirit is forgotten entirely. If it is bound again later, it returns as a new spirit: use count 1 and unsealed.
examples
- case 1
capacity 2; bind a 10, bind b 20, summon a, bind c 30, then held()true, true, 10, true. b is released because it was used once and a twice. held() is ["a", "c"] - case 2
capacity 2; bind a 1, bind b 2, summon a, summon b, bind c 3, then held()c's bind returns true and releases a: both were used twice, and a's last use was earlier. held() is ["b", "c"] - case 3
capacity 2; bind a 1, bind b 2, seal a, seal b, bind c 3, then held()bind c returns false because every held spirit is sealed. Nothing changes, and held() is ["a", "b"] - case 4
capacity 2; bind a 1, bind b 2, bind a 9, bind c 3, then held()All four binds return true. Rebinding a releases nothing and counts as a use, so c's arrival releases b. held() is ["a", "c"]
- reward
- 540 XP
- signature
SpiritRack
TypeScript, run as ES2022 — types are stripped, not checked. If a JS engine would run it, so will we.
- use count decides release
- earliest last use breaks ties
- sealed spirit is skipped
- all sealed refuses the bind
- capacity zero holds nothing
- rebind updates without releasing
- released spirit returns fresh
- sealing is not a use
- rebinding keeps the seal