Try it yourself. Each card shows a tiny program. Predict whether it halts or loops forever, then reveal the answer.
<p class="hint">Read each tiny program and predict: does it <b>halt</b> (stop) or <b>loop forever</b>? Click your guess, then reveal the answer. The last one is special.</p>
<div class="card">
<div class="counter"><span id="idx">1</span> / <span id="n">0</span> · score <span id="score">0</span></div>
<pre id="code" class="code"></pre>
<div class="btns">
<button id="halts" type="button">Halts</button>
<button id="loops" type="button">Loops forever</button>
</div>
<div id="verdict" class="verdict"></div>
<button id="next" type="button" class="next" hidden>Next program →</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.card { border: 1px solid #e2e6eb; border-radius: 12px; padding: 1rem; background: #fff; }
.counter { font: 600 13px system-ui; color: #777; margin-bottom: .5rem; }
.code { background: #1d2733; color: #e6edf3; border-radius: 8px; padding: .8rem 1rem; font: 600 13.5px ui-monospace, monospace; line-height: 1.5; overflow-x: auto; white-space: pre; margin: 0 0 .8rem; }
.btns { display: flex; gap: .6rem; }
button { font: 600 14px system-ui, sans-serif; padding: .55rem 1.1rem; border-radius: 8px; cursor: pointer; border: 1px solid #457b9d; background: #457b9d; color: #fff; }
.btns button { flex: 1; }
#loops { background: #fff; color: #457b9d; }
button:disabled { opacity: .5; cursor: default; }
.verdict { min-height: 1.4em; margin: .8rem 0 0; font-size: .95rem; line-height: 1.5; }
.verdict.ok { color: #0a7d33; }
.verdict.bad { color: #c0392b; }
.verdict b { font-weight: 800; }
.verdict .para { color: #6d28d9; }
.next { background: #2a9d8f; border-color: #2a9d8f; margin-top: .8rem; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// A halting guessing game. The first programs are decidable by eye; the last is the diagonalization "paradox machine" that defeats ANY would-be halting detector H — the heart of Turing’s 1936 proof.
const PROGS = [
{ code: "x = 0\nwhile x < 10:\n x = x + 1\nprint(x)", halts: true,
why: "x climbs 0→10 and the loop stops. Clearly halts." },
{ code: "x = 1\nwhile x > 0:\n x = x + 1", halts: false,
why: "x only grows, so x > 0 is always true. Loops forever." },
{ code: "n = 27\nwhile n != 1:\n if n % 2 == 0: n = n // 2\n else: n = 3*n + 1", halts: true,
why: "This is the Collatz sequence from 27 — it does reach 1 (after 111 steps). Halts. But whether it halts for EVERY n is an open problem no one can prove!" },
{ code: "while True:\n pass", halts: false,
why: "An explicit infinite loop. Loops forever." },
{ code: "for i in range(1000000):\n pass\nprint('done')", halts: true,
why: "A finite, if long, loop. Halts." },
{ code: "# The paradox machine T(T):\n# if H says T halts -> loop forever\n# if H says T loops -> halt\nrun_opposite_of( H(T, T) )", halts: null,
why: "There is no right answer — and that’s the point. Whatever a perfect detector H predicts about this self-referential program, T is built to do the opposite. H must be wrong about T. So H cannot exist: halting is undecidable." }
];
let i = 0, score = 0, answered = false;
const $ = id => document.getElementById(id);
function show() {
answered = false;
const p = PROGS[i];
$('idx').textContent = i + 1;
$('n').textContent = PROGS.length;
$('score').textContent = score;
$('code').textContent = p.code;
$('verdict').textContent = '';
$('verdict').className = 'verdict';
$('next').hidden = true;
$('halts').disabled = false;
$('loops').disabled = false;
}
function answer(guessHalts) {
if (answered) return;
answered = true;
const p = PROGS[i];
$('halts').disabled = true;
$('loops').disabled = true;
const v = $('verdict');
if (p.halts === null) {
v.className = 'verdict';
v.innerHTML = fmt('<b class="para">The paradox machine.</b> %why%', { why: p.why });
} else {
const correct = guessHalts === p.halts;
if (correct) score++;
v.className = 'verdict ' + (correct ? 'ok' : 'bad');
v.innerHTML = fmt('<b>%v%</b> It %v2%%why%', { v: correct ? 'Correct!' : 'Not quite.', v2: p.halts ? 'halts. ' : 'loops forever. ', why: p.why });
}
$('score').textContent = score;
if (i < PROGS.length - 1) $('next').hidden = false;
else { $('next').hidden = false; $('next').textContent = 'Start over ↺'; }
}
$('halts').addEventListener('click', () => answer(true));
$('loops').addEventListener('click', () => answer(false));
$('next').addEventListener('click', () => { i = (i + 1) % PROGS.length; if (i === 0) score = 0; $('next').textContent = 'Next program →'; show(); });
show();
<p class="hint">Read each tiny program and predict: does it <b>halt</b> (stop) or <b>loop forever</b>? Click your guess, then reveal the answer. The last one is special.</p>
<div class="card">
<div class="counter"><span id="idx">1</span> / <span id="n">0</span> · score <span id="score">0</span></div>
<pre id="code" class="code"></pre>
<div class="btns">
<button id="halts" type="button">Halts</button>
<button id="loops" type="button">Loops forever</button>
</div>
<div id="verdict" class="verdict"></div>
<button id="next" type="button" class="next" hidden>Next program →</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.card { border: 1px solid #e2e6eb; border-radius: 12px; padding: 1rem; background: #fff; }
.counter { font: 600 13px system-ui; color: #777; margin-bottom: .5rem; }
.code { background: #1d2733; color: #e6edf3; border-radius: 8px; padding: .8rem 1rem; font: 600 13.5px ui-monospace, monospace; line-height: 1.5; overflow-x: auto; white-space: pre; margin: 0 0 .8rem; }
.btns { display: flex; gap: .6rem; }
button { font: 600 14px system-ui, sans-serif; padding: .55rem 1.1rem; border-radius: 8px; cursor: pointer; border: 1px solid #457b9d; background: #457b9d; color: #fff; }
.btns button { flex: 1; }
#loops { background: #fff; color: #457b9d; }
button:disabled { opacity: .5; cursor: default; }
.verdict { min-height: 1.4em; margin: .8rem 0 0; font-size: .95rem; line-height: 1.5; }
.verdict.ok { color: #0a7d33; }
.verdict.bad { color: #c0392b; }
.verdict b { font-weight: 800; }
.verdict .para { color: #6d28d9; }
.next { background: #2a9d8f; border-color: #2a9d8f; margin-top: .8rem; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// A halting guessing game. The first programs are decidable by eye; the last is the diagonalization "paradox machine" that defeats ANY would-be halting detector H — the heart of Turing’s 1936 proof.
const PROGS = [
{ code: "x = 0\nwhile x < 10:\n x = x + 1\nprint(x)", halts: true,
why: "x climbs 0→10 and the loop stops. Clearly halts." },
{ code: "x = 1\nwhile x > 0:\n x = x + 1", halts: false,
why: "x only grows, so x > 0 is always true. Loops forever." },
{ code: "n = 27\nwhile n != 1:\n if n % 2 == 0: n = n // 2\n else: n = 3*n + 1", halts: true,
why: "This is the Collatz sequence from 27 — it does reach 1 (after 111 steps). Halts. But whether it halts for EVERY n is an open problem no one can prove!" },
{ code: "while True:\n pass", halts: false,
why: "An explicit infinite loop. Loops forever." },
{ code: "for i in range(1000000):\n pass\nprint('done')", halts: true,
why: "A finite, if long, loop. Halts." },
{ code: "# The paradox machine T(T):\n# if H says T halts -> loop forever\n# if H says T loops -> halt\nrun_opposite_of( H(T, T) )", halts: null,
why: "There is no right answer — and that’s the point. Whatever a perfect detector H predicts about this self-referential program, T is built to do the opposite. H must be wrong about T. So H cannot exist: halting is undecidable." }
];
let i = 0, score = 0, answered = false;
const $ = id => document.getElementById(id);
function show() {
answered = false;
const p = PROGS[i];
$('idx').textContent = i + 1;
$('n').textContent = PROGS.length;
$('score').textContent = score;
$('code').textContent = p.code;
$('verdict').textContent = '';
$('verdict').className = 'verdict';
$('next').hidden = true;
$('halts').disabled = false;
$('loops').disabled = false;
}
function answer(guessHalts) {
if (answered) return;
answered = true;
const p = PROGS[i];
$('halts').disabled = true;
$('loops').disabled = true;
const v = $('verdict');
if (p.halts === null) {
v.className = 'verdict';
v.innerHTML = fmt('<b class="para">The paradox machine.</b> %why%', { why: p.why });
} else {
const correct = guessHalts === p.halts;
if (correct) score++;
v.className = 'verdict ' + (correct ? 'ok' : 'bad');
v.innerHTML = fmt('<b>%v%</b> It %v2%%why%', { v: correct ? 'Correct!' : 'Not quite.', v2: p.halts ? 'halts. ' : 'loops forever. ', why: p.why });
}
$('score').textContent = score;
if (i < PROGS.length - 1) $('next').hidden = false;
else { $('next').hidden = false; $('next').textContent = 'Start over ↺'; }
}
$('halts').addEventListener('click', () => answer(true));
$('loops').addEventListener('click', () => answer(false));
$('next').addEventListener('click', () => { i = (i + 1) % PROGS.length; if (i === 0) score = 0; $('next').textContent = 'Next program →'; show(); });
show();