‹ back to the board

Saturday, September 12

Mastermulti-constraint & composite logic

The Cellar of Sealed Casks

The inn at bitwick keeps a cellar with room for a fixed number of casks. Every cask has a name and a tier (an integer from 0 to 9, higher is finer), and every cask is either sealed or unsealed. When a cask arrives at a full cellar, something has to leave.

Build Cellar, constructed with capacity, an integer of 0 or more.

A cask is touched when it is successfully stored and when it is poured. Nothing else touches a cask. No two touches happen at the same moment, so "least recently touched" always names exactly one cask.

`store(name, tier)` — name is a string, tier an integer from 0 to 9. Returns a string or null:

  • If a cask called name is already in the cellar: set its tier to tier, touch it, return null. Nothing is evicted and its seal is unchanged.
  • Otherwise, if the cellar holds fewer than capacity casks: add it, unsealed, touch it, return null.
  • Otherwise the cellar is full. If at least one cask in it is unsealed, remove one of them — the unsealed cask of lowest tier, and among those the least recently touched — then add the arriving cask, unsealed and touched, and return the removed cask's name. The arriving cask's own tier plays no part in choosing which cask is removed.
  • Otherwise (full, with no unsealed cask in it) the arriving cask is not stored at all, the cellar is unchanged, and the return value is name itself.

`pour(name)` — if that cask is in the cellar, touch it and return its tier (an integer). If it is not, change nothing and return -1.

`seal(name)` — if that cask is in the cellar, mark it sealed and return true; sealing an already-sealed cask still returns true. If it is not there, change nothing and return false. Sealing does not touch a cask.

`unseal(name)` — the same, but marking the cask unsealed.

`contents()` — returns the names of the casks currently in the cellar, as a list of strings, ordered by tier descending; casks of equal tier are ordered most recently touched first.

  • stateful objects with eviction rules
  • Master

examples

  1. case 1capacity 3; store "ale" at tier 2, store "mead" at tier 1, store "cider" at tier 2, pour "mead", store "perry" at tier 3the store of "perry" returns "mead" — mead has the lowest tier even though it was just poured — and contents() is ["perry", "cider", "ale"]
  2. case 2capacity 2; store "brine" at tier 0, store "stout" at tier 5, seal "brine", store "porter" at tier 9, seal "porter", store "small" at tier 1storing "porter" returns "stout" (brine is sealed and passed over); storing "small" returns "small", since every cask in the full cellar is sealed, and the cellar keeps porter and brine
  3. case 3capacity 0; store "ale" at tier 3, then contents()the store returns "ale" and contents() is the empty list
reward
500 XP
signature
Cellar
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…
  • lowest tier loses before least recently touched
  • sealed casks are passed over and a wholly sealed cellar refuses
  • a cellar of capacity zero turns everything away
  • restoring a name re-tiers it without evicting anything
  • unsealing restores eligibility and the newcomer may rank lower
The Cellar of Sealed Casks · bitwick