Advanced

Recording and replaying a run

A rare bug that cannot be reproduced cannot be fixed. The record is the seed plus the inputs per step, and the replay feeds them back into the same rules. If the rules are pure, the replay reaches the same state and the bug is visible.

What you will see

Equal. Unequal means a rule reads the clock or Math.random, and that rule is the bug.

About 1 min of reading

Try It

Record one run and replay it

1

Write the record

printf 'const rec = { seed: 7, inputs: [] }; function step(w, input) { rec.inputs.push(input); return apply(w, input); } ' | tee game/rec.js

Before you run it, say out loud what it will print. Then open the answer.

What it prints
One number per step. The record is printable as JSON.
2

Save it

printf 'JSON.stringify(rec) ' | tee -a game/rec.js; node -e 'console.log(JSON.stringify({seed:7,inputs:[0,1,1,0,2]}))'

Before you run it, say out loud what it will print. Then open the answer.

What it prints
One short line. A run that fits in a line is a run anyone can paste.
3

Replay it

printf 'function replay(r) { let w = fresh(r.seed); r.inputs.forEach((i, n) => apply(w, i)); return w; } ' | tee -a game/rec.js

Before you run it, say out loud what it will print. Then open the answer.

What it prints
The same rules, the same inputs, a fresh state. No drawing and no clock involved.
4

Compare the checksums

print a checksum of the state at step 50 in the live run and in the replay

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Equal. Unequal means a rule reads the clock or Math.random, and that rule is the bug.
Do not record the state every step. Recording states cannot show how a bug arose, and it is also much bigger.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Run to a record to a replay
1 Seed the generator
↓
2 Record one input per step
↓
3 Feed the inputs back to the rules
↓
4 Compare state checksums at checkpoints
Why this works
What the record is not

It is not a save file. A save file is a state; a record is the path to a state, and only the path shows how the bug happened.

Where the record grows

One value per step is small, but a long run is still long. Store the seed and the input stream, and compress only if it stops fitting.

Examples

Record the smallest thing

The seed and one input value per step. Not screenshots and not logs, which cannot be fed back in.

Replay to a step number

Run the rules with the recorded inputs until the step where the bug appeared. The state there is the state to inspect.

Fail the replay if it drifts

Compare a checksum of the state at a few steps. A replay that drifts means a rule is not pure, and that is the finding.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Difficulty as data, and the curve it produces
Previous Lesson
Difficulty as data, and the curve it produces
Next Lesson
Juice: making the state visible without changing it
Juice: making the state visible without changing it →