Lander starts a flight where a flight starts

run does not reload, and that is right: run's job is to run the program
that is loaded, which is why it is a separate word from load and why
typing a program's name does both. What follows is that the numbers the
assembler wrote into a Data Segment are LOAD-time values, true once, and
a program that wants them true at every start has to say so itself.

Lander did not. Flying is 0x01 in the data and is only ever cleared, so a
second run began with the loop already over: the program started and
handed the machine straight back. Reproduced by running it, quitting, and
running again - the leftover game keys land at the shell prompt, which is
what a program that never read them looks like.

AND THE TEST FOUND A SECOND ONE, quieter and worse. The terrain seed is a
written number, so a fresh load always walks out the same moon - but
nextRandom moves it, and a second run generated a DIFFERENT moon. Nobody
decided that. A test comparing the whole screen found it without anybody
having had to think of it in advance, which is the argument for comparing
the picture rather than the variables somebody remembered to check.

Only what a flight needs to begin is put back. Anything not on the list
keeps what the last run left it, which is deliberate - state surviving a
run is sometimes exactly what is wanted, and the way to have that is for
the list to be a decision rather than a sweep. The things that are simply
nought are a table of NAMES that the assembler turns into addresses, so
adding a variable that must start empty means adding it there and nowhere
else.

video.sh now runs Lander, quits, runs it again, and requires the same
picture a hundred frames in - the same moon, the same lander in the same
place, the same gauges. break.sh confirms it by taking the seed line back
out: 37,995 bytes of the picture differ.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-06 09:02:50 -04:00
co-authored by Claude Opus 5
parent b160c66110
commit 87467a7d3a
13 changed files with 144 additions and 11 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -32,7 +32,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -108,7 +108,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -27,7 +27,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -15,7 +15,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -13,7 +13,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+1 -1
View File
@@ -22,7 +22,7 @@ Mode.sbx 48
Flip.sbx 173
Sprite.sbx 442
Depth.sbx 672
Lander.sbx 9201
Lander.sbx 9361
Pad.sbx 264
Crash.sbx 632
vars.script 50
+38
View File
@@ -3249,6 +3249,44 @@ PY2
)"
[ "$LETTERS" = "16" ] && result ok "and does not rub out what it moves over" "all sixteen letters are still there" || result no "and does not rub out what it moves over" "$LETTERS of sixteen cells still have ink"
# ---- Running a program twice is the same as running it once ----
#
# RUN DOES NOT RELOAD, and that is right: run's job is to run the program that is loaded,
# which is why it is a separate word from load and why typing a program's name does both. It
# follows that the numbers the assembler wrote into a Data Segment are LOAD-time values, true
# once - and a program that wants them true at every start has to say so itself.
#
# Lander did not. A second run began with Flying already nought, so the loop ended before it
# started and the program handed the machine straight back. Worse and quieter: the terrain
# seed is a written number, so a fresh load always walks out the same moon - but nextRandom
# moves it, and a second run generated a different moon, which was nobody's decision.
#
# THE CHECK IS THE WHOLE SCREEN, because that is the only thing that knows about all of it at
# once. A hundred frames in, run once and run twice have to be the same picture: the same
# moon, the same lander in the same place, the same gauges. Any state that survives a run and
# should not shows up here without anybody having to have thought of it in advance.
python3 -c "
open('$BUILD/once.keys','wb').write(b'Lander\n' + b'\x00'*100)
open('$BUILD/twice.keys','wb').write(b'Lander\n' + b'\x00'*100 + b'q' + b'\x00'*20 + b'run\n' + b'\x00'*100)
open('$BUILD/still.pad','wb').write(b'\x00' * 20000)"
for WHEN in once twice; do
timeout 60 "$EMU" --fast --cycles 24000000 --keyboard "$BUILD/$WHEN.keys" \
--pad "$BUILD/still.pad" --screen "$BUILD/run$WHEN.ppm" \
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
"$BUILD/cosmos.bin" > "$BUILD/run$WHEN.out" 2>&1 || true
done
if [ ! -f "$BUILD/runonce.ppm" ] || [ ! -f "$BUILD/runtwice.ppm" ]; then
result no "a program run twice starts where it started" "no picture came out"
elif cmp -s "$BUILD/runonce.ppm" "$BUILD/runtwice.ppm"; then
result ok "a program run twice starts where it started" "the same screen a hundred frames in"
else
DIFFERS="$(python3 -c "
a = open('$BUILD/runonce.ppm','rb').read()
b = open('$BUILD/runtwice.ppm','rb').read()
print(sum(1 for x, y in zip(a, b) if x != y))")"
result no "a program run twice starts where it started" "$DIFFERS bytes of the picture differ"
fi
echo
if [ "$FAIL" -eq 0 ]; then
echo "All $PASS video checks passed."