<!-- 6x6 officer placement grid — rank (A-F) x regiment (1-6) -->
<p class="hint">Click any cell to place an officer. Each officer is identified by their <b>rank</b> (A–F) and <b>regiment</b> (1–6). Goal: every row and every column must contain each rank exactly once AND each regiment exactly once. Conflicts light up red. Can you fill all 36 cells without a single conflict?</p>
<div id="legend" class="legend">
<span class="leg-label">Rank:</span>
<span class="leg-item rank-A">A</span><span class="leg-item rank-B">B</span><span class="leg-item rank-C">C</span><span class="leg-item rank-D">D</span><span class="leg-item rank-E">E</span><span class="leg-item rank-F">F</span>
<span class="leg-sep"></span>
<span class="leg-label">Regiment:</span>
<span class="leg-item reg-1">1</span><span class="leg-item reg-2">2</span><span class="leg-item reg-3">3</span><span class="leg-item reg-4">4</span><span class="leg-item reg-5">5</span><span class="leg-item reg-6">6</span>
</div>
<div id="board" class="board" aria-label="6 by 6 officer placement grid"></div>
<div id="status" class="status" aria-live="polite">Click a cell to place your first officer.</div>
<div class="btns">
<button id="btn-check" type="button">Check grid</button>
<button id="btn-hint" type="button">Why is it impossible?</button>
<button id="btn-reset" type="button" class="ghost">Clear grid</button>
</div>
/* Styles for the 36-officers demo */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .87rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.legend { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; margin-bottom: .5rem; font-size: .8rem; }
.leg-label { font-weight: 700; color: #555; margin-right: .1rem; }
.leg-sep { width: .7rem; }
.leg-item { display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px;
border-radius:4px; font-weight:700; font-size:.78rem; border:1px solid #ccc; }
.board { display: grid; grid-template-columns: repeat(6, 46px); gap: 3px; margin: .3rem 0; }
.cell { width: 46px; height: 46px; display: flex; align-items: center; justify-content: center;
font: 700 14px ui-monospace, monospace; border-radius: 7px; cursor: pointer;
user-select: none; border: 2px solid transparent; transition: background .15s, border-color .15s; }
.cell.empty { background: #d2d6db; border-color: #b8bcc2; color: #888; }
.cell.empty::after { content: "·"; font-size: 1.3rem; }
.cell.filled { background: #e8eef3; border-color: #b0c4d8; color: #1d3557; }
.cell.conflict { background: #ffe0e0; border-color: #e63946; color: #c92f3c; }
.cell:hover { filter: brightness(.93); }
/* Subtle background tint per rank to help visual scanning */
.rank-A, .cell[data-rank="A"] { background-color: #dce8f5; }
.rank-B, .cell[data-rank="B"] { background-color: #dcf5e4; }
.rank-C, .cell[data-rank="C"] { background-color: #f5f0dc; }
.rank-D, .cell[data-rank="D"] { background-color: #f5dcf0; }
.rank-E, .cell[data-rank="E"] { background-color: #dce8f5; filter: hue-rotate(40deg); }
.rank-F, .cell[data-rank="F"] { background-color: #f5e4dc; }
.cell.conflict { background: #ffe0e0 !important; border-color: #e63946 !important; }
.status { font-size: .95rem; font-weight: 600; margin: .4rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.status.info { color: #1d3557; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff;
border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// 36 Officers demo: click to cycle through all 36 officer types; conflicts highlighted in red.
const RANKS = ['A','B','C','D','E','F'];
const REGS = [1, 2, 3, 4, 5, 6];
const N = 6;
// 6x6 grid — null means empty, {rank, reg} means occupied
const grid = Array.from({length: N}, () => Array(N).fill(null));
// Return the set of (r,c) keys that participate in any row or column conflict.
function getConflicts() {
const bad = new Set();
// Check rows for duplicate rank or regiment.
for (let r = 0; r < N; r++) {
const rankSeen = {}, regSeen = {};
for (let c = 0; c < N; c++) {
const v = grid[r][c]; if (!v) continue;
if (rankSeen[v.rank] !== undefined) { bad.add(r+','+rankSeen[v.rank]); bad.add(r+','+c); }
else rankSeen[v.rank] = c;
if (regSeen[v.reg] !== undefined) { bad.add(r+','+regSeen[v.reg]); bad.add(r+','+c); }
else regSeen[v.reg] = c;
}
}
// Check columns for duplicate rank or regiment.
for (let c = 0; c < N; c++) {
const rankSeen = {}, regSeen = {};
for (let r = 0; r < N; r++) {
const v = grid[r][c]; if (!v) continue;
if (rankSeen[v.rank] !== undefined) { bad.add(rankSeen[v.rank]+','+c); bad.add(r+','+c); }
else rankSeen[v.rank] = r;
if (regSeen[v.reg] !== undefined) { bad.add(regSeen[v.reg]+','+c); bad.add(r+','+c); }
else regSeen[v.reg] = r;
}
}
return bad;
}
function filled() {
return grid.every(row => row.every(v => v !== null));
}
// Cycle through all 36 officer types on each click; null means remove.
function nextOfficer(cur) {
if (!cur) return { rank: RANKS[0], reg: REGS[0] };
const ri = RANKS.indexOf(cur.rank);
const gi = REGS.indexOf(cur.reg);
const next = ri * N + gi + 1;
if (next >= N * N) return null;
return { rank: RANKS[Math.floor(next / N)], reg: REGS[next % N] };
}
function render() {
const conflicts = getConflicts();
const board = document.getElementById('board');
board.innerHTML = '';
for (let r = 0; r < N; r++) {
for (let c = 0; c < N; c++) {
const cell = document.createElement('div');
const v = grid[r][c];
const key = r+','+c;
if (v) {
cell.className = 'cell filled' + (conflicts.has(key) ? ' conflict' : '');
cell.dataset.rank = v.rank;
cell.textContent = v.rank + v.reg;
cell.title = i18nFmt('Rank %rank%, Regiment %reg%', { rank: v.rank, reg: v.reg });
} else {
cell.className = 'cell empty';
cell.title = 'Click to place an officer';
}
cell.setAttribute('aria-label', v ? i18nFmt('Row %r%, column %c%: rank %rank%, regiment %reg%', { rank: v.rank, reg: v.reg, r: r+1, c: c+1 }) : i18nFmt('Row %r%, column %c%: empty', { r: r+1, c: c+1 }));
cell.addEventListener('click', () => { grid[r][c] = nextOfficer(v); renderAndCheck(); });
board.appendChild(cell);
}
}
}
function setStatus(msg, cls) {
const el = document.getElementById('status');
el.textContent = msg;
el.className = 'status ' + (cls || '');
}
function renderAndCheck() {
render();
const conflicts = getConflicts();
if (conflicts.size === 0 && filled()) {
setStatus('✓ Remarkable — a valid arrangement! (But this is a smaller version; the 6×6 with all 36 distinct officers is impossible.)', 'ok');
} else if (conflicts.size > 0) {
setStatus(i18nFmt('✗ %n% conflict(s) detected — two officers share a rank or regiment in the same row or column.', { n: conflicts.size }), 'bad');
} else {
setStatus('Grid is valid so far — keep placing officers.', 'info');
}
}
// Check button validates the current grid state.
document.getElementById('btn-check').addEventListener('click', () => {
const conflicts = getConflicts();
if (!filled()) {
setStatus('Fill all 36 cells first, then check.', 'info');
} else if (conflicts.size === 0) {
setStatus('✓ Remarkable — a valid arrangement! (But this is a smaller version; the 6×6 with all 36 distinct officers is impossible.)', 'ok');
} else {
setStatus(i18nFmt('✗ %n% conflict(s) detected — two officers share a rank or regiment in the same row or column.', { n: conflicts.size }), 'bad');
}
});
document.getElementById('btn-hint').addEventListener('click', () => {
// Show the impossibility message regardless of current grid state.
setStatus('Tarry proved in 1901 (by checking every case) that no valid 6×6 arrangement of 36 distinct officers exists. There is no solution — not even close!', 'bad');
});
document.getElementById('btn-reset').addEventListener('click', () => {
for (let r = 0; r < N; r++) for (let c = 0; c < N; c++) grid[r][c] = null;
render();
setStatus('Grid cleared. Start over.', '');
});
render();
setStatus('Click a cell to place your first officer.', '');
<!-- 6x6 officer placement grid — rank (A-F) x regiment (1-6) -->
<p class="hint">Click any cell to place an officer. Each officer is identified by their <b>rank</b> (A–F) and <b>regiment</b> (1–6). Goal: every row and every column must contain each rank exactly once AND each regiment exactly once. Conflicts light up red. Can you fill all 36 cells without a single conflict?</p>
<div id="legend" class="legend">
<span class="leg-label">Rank:</span>
<span class="leg-item rank-A">A</span><span class="leg-item rank-B">B</span><span class="leg-item rank-C">C</span><span class="leg-item rank-D">D</span><span class="leg-item rank-E">E</span><span class="leg-item rank-F">F</span>
<span class="leg-sep"></span>
<span class="leg-label">Regiment:</span>
<span class="leg-item reg-1">1</span><span class="leg-item reg-2">2</span><span class="leg-item reg-3">3</span><span class="leg-item reg-4">4</span><span class="leg-item reg-5">5</span><span class="leg-item reg-6">6</span>
</div>
<div id="board" class="board" aria-label="6 by 6 officer placement grid"></div>
<div id="status" class="status" aria-live="polite">Click a cell to place your first officer.</div>
<div class="btns">
<button id="btn-check" type="button">Check grid</button>
<button id="btn-hint" type="button">Why is it impossible?</button>
<button id="btn-reset" type="button" class="ghost">Clear grid</button>
</div>
/* Styles for the 36-officers demo */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .87rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.legend { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; margin-bottom: .5rem; font-size: .8rem; }
.leg-label { font-weight: 700; color: #555; margin-right: .1rem; }
.leg-sep { width: .7rem; }
.leg-item { display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px;
border-radius:4px; font-weight:700; font-size:.78rem; border:1px solid #ccc; }
.board { display: grid; grid-template-columns: repeat(6, 46px); gap: 3px; margin: .3rem 0; }
.cell { width: 46px; height: 46px; display: flex; align-items: center; justify-content: center;
font: 700 14px ui-monospace, monospace; border-radius: 7px; cursor: pointer;
user-select: none; border: 2px solid transparent; transition: background .15s, border-color .15s; }
.cell.empty { background: #d2d6db; border-color: #b8bcc2; color: #888; }
.cell.empty::after { content: "·"; font-size: 1.3rem; }
.cell.filled { background: #e8eef3; border-color: #b0c4d8; color: #1d3557; }
.cell.conflict { background: #ffe0e0; border-color: #e63946; color: #c92f3c; }
.cell:hover { filter: brightness(.93); }
/* Subtle background tint per rank to help visual scanning */
.rank-A, .cell[data-rank="A"] { background-color: #dce8f5; }
.rank-B, .cell[data-rank="B"] { background-color: #dcf5e4; }
.rank-C, .cell[data-rank="C"] { background-color: #f5f0dc; }
.rank-D, .cell[data-rank="D"] { background-color: #f5dcf0; }
.rank-E, .cell[data-rank="E"] { background-color: #dce8f5; filter: hue-rotate(40deg); }
.rank-F, .cell[data-rank="F"] { background-color: #f5e4dc; }
.cell.conflict { background: #ffe0e0 !important; border-color: #e63946 !important; }
.status { font-size: .95rem; font-weight: 600; margin: .4rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.status.info { color: #1d3557; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .85rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff;
border-radius: 7px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// 36 Officers demo: click to cycle through all 36 officer types; conflicts highlighted in red.
const RANKS = ['A','B','C','D','E','F'];
const REGS = [1, 2, 3, 4, 5, 6];
const N = 6;
// 6x6 grid — null means empty, {rank, reg} means occupied
const grid = Array.from({length: N}, () => Array(N).fill(null));
// Return the set of (r,c) keys that participate in any row or column conflict.
function getConflicts() {
const bad = new Set();
// Check rows for duplicate rank or regiment.
for (let r = 0; r < N; r++) {
const rankSeen = {}, regSeen = {};
for (let c = 0; c < N; c++) {
const v = grid[r][c]; if (!v) continue;
if (rankSeen[v.rank] !== undefined) { bad.add(r+','+rankSeen[v.rank]); bad.add(r+','+c); }
else rankSeen[v.rank] = c;
if (regSeen[v.reg] !== undefined) { bad.add(r+','+regSeen[v.reg]); bad.add(r+','+c); }
else regSeen[v.reg] = c;
}
}
// Check columns for duplicate rank or regiment.
for (let c = 0; c < N; c++) {
const rankSeen = {}, regSeen = {};
for (let r = 0; r < N; r++) {
const v = grid[r][c]; if (!v) continue;
if (rankSeen[v.rank] !== undefined) { bad.add(rankSeen[v.rank]+','+c); bad.add(r+','+c); }
else rankSeen[v.rank] = r;
if (regSeen[v.reg] !== undefined) { bad.add(regSeen[v.reg]+','+c); bad.add(r+','+c); }
else regSeen[v.reg] = r;
}
}
return bad;
}
function filled() {
return grid.every(row => row.every(v => v !== null));
}
// Cycle through all 36 officer types on each click; null means remove.
function nextOfficer(cur) {
if (!cur) return { rank: RANKS[0], reg: REGS[0] };
const ri = RANKS.indexOf(cur.rank);
const gi = REGS.indexOf(cur.reg);
const next = ri * N + gi + 1;
if (next >= N * N) return null;
return { rank: RANKS[Math.floor(next / N)], reg: REGS[next % N] };
}
function render() {
const conflicts = getConflicts();
const board = document.getElementById('board');
board.innerHTML = '';
for (let r = 0; r < N; r++) {
for (let c = 0; c < N; c++) {
const cell = document.createElement('div');
const v = grid[r][c];
const key = r+','+c;
if (v) {
cell.className = 'cell filled' + (conflicts.has(key) ? ' conflict' : '');
cell.dataset.rank = v.rank;
cell.textContent = v.rank + v.reg;
cell.title = i18nFmt('Rank %rank%, Regiment %reg%', { rank: v.rank, reg: v.reg });
} else {
cell.className = 'cell empty';
cell.title = 'Click to place an officer';
}
cell.setAttribute('aria-label', v ? i18nFmt('Row %r%, column %c%: rank %rank%, regiment %reg%', { rank: v.rank, reg: v.reg, r: r+1, c: c+1 }) : i18nFmt('Row %r%, column %c%: empty', { r: r+1, c: c+1 }));
cell.addEventListener('click', () => { grid[r][c] = nextOfficer(v); renderAndCheck(); });
board.appendChild(cell);
}
}
}
function setStatus(msg, cls) {
const el = document.getElementById('status');
el.textContent = msg;
el.className = 'status ' + (cls || '');
}
function renderAndCheck() {
render();
const conflicts = getConflicts();
if (conflicts.size === 0 && filled()) {
setStatus('✓ Remarkable — a valid arrangement! (But this is a smaller version; the 6×6 with all 36 distinct officers is impossible.)', 'ok');
} else if (conflicts.size > 0) {
setStatus(i18nFmt('✗ %n% conflict(s) detected — two officers share a rank or regiment in the same row or column.', { n: conflicts.size }), 'bad');
} else {
setStatus('Grid is valid so far — keep placing officers.', 'info');
}
}
// Check button validates the current grid state.
document.getElementById('btn-check').addEventListener('click', () => {
const conflicts = getConflicts();
if (!filled()) {
setStatus('Fill all 36 cells first, then check.', 'info');
} else if (conflicts.size === 0) {
setStatus('✓ Remarkable — a valid arrangement! (But this is a smaller version; the 6×6 with all 36 distinct officers is impossible.)', 'ok');
} else {
setStatus(i18nFmt('✗ %n% conflict(s) detected — two officers share a rank or regiment in the same row or column.', { n: conflicts.size }), 'bad');
}
});
document.getElementById('btn-hint').addEventListener('click', () => {
// Show the impossibility message regardless of current grid state.
setStatus('Tarry proved in 1901 (by checking every case) that no valid 6×6 arrangement of 36 distinct officers exists. There is no solution — not even close!', 'bad');
});
document.getElementById('btn-reset').addEventListener('click', () => {
for (let r = 0; r < N; r++) for (let c = 0; c < N; c++) grid[r][c] = null;
render();
setStatus('Grid cleared. Start over.', '');
});
render();
setStatus('Click a cell to place your first officer.', '');
Notice how a conflict appears the moment you try to fill the last rows. In every other order — 3×3, 4×4, 5×5 — a perfect arrangement exists. The 6×6 case is uniquely defiant. Euler sensed this but could not prove it; it took Tarry 119 years later to check all 9×1021 essentially different grids and confirm: no solution exists.
Comments
Loading comments...