# The Oracle's Chest: how it is built

Prophecy, rewind and the other life from the kit's saves engine: the whole game is a seed and a string of digits.

## What it imports

```html
<script src="../../../sitoolz/js/blake2b.js"></script><script src="../../../sitoolz/js/rangeblends.js"></script><script src="../../../sitoolz/js/rulerland.js"></script>
<script src="../../../sitoolz/js/qrand.js"></script><script src="../../../sitoolz/js/indexrng.js"></script>
<script src="../../../sitoolz/js/saves.js"></script>   <!-- SISaves: encode, decode, rewind, branch, replay, lootAt, prophecy -->
```

## The twenty lines that make it

```js
const TABLE = ["a brass lamp", "a silver coin", "an iron key", "a folded map", "a cracked mirror", "nothing at all", "a ruby", "a loaf of bread"];
const DIRS = {0: [-1, 0], 1: [0, 1], 2: [1, 0], 3: [0, -1]};            // a choice is one digit: 0 north, 1 east, 2 south, 3 west, 4 open
function step(st, c, i, seed){                                          // the game is a fold over the choices, from nothing but the string
  if (c <= 3){ const [dr, dc] = DIRS[c], r = Math.floor(st.room/3) + dr, cc = st.room % 3 + dc; if (r >= 0 && r < 3 && cc >= 0 && cc < 3) st.room = r*3 + cc; return st; }
  if (c === 4 && st.room >= 1 && st.room <= 6 && !st.opened[st.room]) st.opened[st.room] = SISaves.lootAt(seed, st.room, 0, TABLE);   // the chest is a lookup
  return st; }
const state = (seed, choices) => SISaves.replay(SISaves.encode(seed, choices), step, {room: 0, opened: {}});
const oracle = SISaves.prophecy(seed, [1, 2, 3, 4, 5, 6], 0, TABLE);   // the same lookup, made six times before any chest is opened
const save = SISaves.encode(seed, choices);                             // "lars@1424": the URL is the save
const earlier = SISaves.rewind(save, 2);                                // "lars@14": rewinding is slicing
const other = SISaves.branch(save, 1, 2);                               // "lars@12": the other life, recomputed from the same seed
```

## How to change the law

- The loot table is the only content: change `TABLE` and the oracle changes with it, because she reads the same table.
- `lootAt(seed, chest, slot, table)` takes a slot: slot 1 could be a second item in every chest, or a trap, and a second oracle could foretell it.
- More rooms or more choices per digit: base 36 allows 36 choices a step (`SISaves.ALPHABET`); the fold function is the whole game.
- The seed is the world: a different seed gives different chests, and the URL carries both, so a link is a complete replay.

## How to verify it

`fixtures/saves.json` (from `tests/write_saves_fixture.py`) holds saves, rewinds, branches, replays through a fold, eighteen lookups and two prophecies, checked by `tests/twins-saves.test.cjs`; `indexrng`'s own fixture checks the draws behind `lootAt`. The smoke here opens two chests, checks each item against `lootAt` directly, rewinds to `lars@14` and branches to `lars@12`.

## What was missing

Nothing.

![](shot.png)
