An editing pass over the words around the game

The hall, the guide, the rules page, the lobby and the report slip lose
most of their semicolons, the statement-colon lines and the guide
narrating itself. The tagline is one sentence, 'a labor of love' is gone
from the about link, and the shared parts read as Waving Hands' do.

Corrected along the way: the about panel no longer says players are shown
only what the rules let them see (nothing in hnefatafl is hidden); the
game was played for centuries before chess, not a thousand years; the
report slip's example no longer mentions points; and a watcher is no
longer told that "your defender" was taken. The move story reads "Ada
moved an attacker from d1 to d4" rather than "Ada: an attacker...".

The end-of-game reasons are unchanged: ledgers record them verbatim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
Eric Wagoner
2026-10-11 10:25:14 -04:00
co-authored by Claude Opus 5.5
parent 7f66be8016
commit 9afe9333c2
10 changed files with 58 additions and 56 deletions
+3 -3
View File
@@ -6,21 +6,21 @@
<meta name="color-scheme" content="dark" /> <meta name="color-scheme" content="dark" />
<meta name="theme-color" content="#14181a" /> <meta name="theme-color" content="#14181a" />
<title>Hnefatafl</title> <title>Hnefatafl</title>
<meta name="description" content="Hnefatafl, the Viking board game, free in the browser: play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." /> <meta name="description" content="Hnefatafl, the Viking board game, free in the browser. Play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." />
<link rel="canonical" href="https://tafl.kestrelsnest.social/" /> <link rel="canonical" href="https://tafl.kestrelsnest.social/" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="Hnefatafl" /> <meta property="og:site_name" content="Hnefatafl" />
<meta property="og:title" content="Hnefatafl" /> <meta property="og:title" content="Hnefatafl" />
<meta property="og:description" content="Hnefatafl, the Viking board game, free in the browser: play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." /> <meta property="og:description" content="Hnefatafl, the Viking board game, free in the browser. Play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." />
<meta property="og:url" content="https://tafl.kestrelsnest.social/" /> <meta property="og:url" content="https://tafl.kestrelsnest.social/" />
<meta property="og:image" content="https://tafl.kestrelsnest.social/og.png" /> <meta property="og:image" content="https://tafl.kestrelsnest.social/og.png" />
<meta property="og:image:width" content="1200" /> <meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" /> <meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Hnefatafl" /> <meta name="twitter:title" content="Hnefatafl" />
<meta name="twitter:description" content="Hnefatafl, the Viking board game, free in the browser: play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." /> <meta name="twitter:description" content="Hnefatafl, the Viking board game, free in the browser. Play a housecarl or a friend, by Copenhagen rules or Linnaeus's Tablut." />
<meta name="twitter:image" content="https://tafl.kestrelsnest.social/og.png" /> <meta name="twitter:image" content="https://tafl.kestrelsnest.social/og.png" />
%sveltekit.head% %sveltekit.head%
</head> </head>
+3 -2
View File
@@ -106,13 +106,14 @@
const side = sideOfPly(ply); const side = sideOfPly(ply);
const yours = !!mySide && mySide === side; const yours = !!mySide && mySide === side;
const who = yours ? 'You' : nameOfSide(side); const who = yours ? 'You' : nameOfSide(side);
const theirs = !!mySide && !yours;
const moverPiece = ply === g.moves.length ? (g.cells[m.to] ?? '.') : '.'; const moverPiece = ply === g.moves.length ? (g.cells[m.to] ?? '.') : '.';
const moverWord = moverPiece !== '.' ? pieceWord(moverPiece) : side === 'attackers' ? 'an attacker' : 'a piece'; const moverWord = moverPiece !== '.' ? pieceWord(moverPiece) : side === 'attackers' ? 'an attacker' : 'a piece';
let text = `${who}: ${moverWord} from ${label(m.from)} to ${label(m.to)}.`; let text = `${who} moved ${moverWord} from ${label(m.from)} to ${label(m.to)}.`;
for (const c of m.captured) { for (const c of m.captured) {
const anvil = beyond(size, m.to, c); const anvil = beyond(size, m.to, c);
const kingFell = side === 'attackers' && !g.cells.includes('k') && ply === g.moves.length; const kingFell = side === 'attackers' && !g.cells.includes('k') && ply === g.moves.length;
const victim = kingFell ? 'the king' : side === 'attackers' ? (yours ? 'a defender' : 'your defender') : yours ? 'an attacker' : 'your attacker'; const victim = kingFell ? 'the king' : side === 'attackers' ? (theirs ? 'your defender' : 'a defender') : theirs ? 'your attacker' : 'an attacker';
const against = const against =
anvil === -1 anvil === -1
? 'the edge' ? 'the edge'
+11 -11
View File
@@ -195,9 +195,9 @@
<section class="lid"> <section class="lid">
<div class="lid-head"> <div class="lid-head">
<h1>Hnefatafl</h1> <h1>Hnefatafl</h1>
<p class="pitch">The Viking board game. One king, one throne, four corners, and a ring of attackers closing in.</p> <p class="pitch">The Viking board game of a king breaking for safety and a ring of attackers closing in.</p>
<p class="tag">Hnefatafl was played across the Norse world for a thousand years before chess. Every piece moves like a rook and is taken by being sandwiched; the attackers must capture the king, the king must reach safety. Play a housecarl, or open a table for a friend and play by turns. Copenhagen rules on the big board, or Tablut, the older game Linnaeus wrote down in 1732.</p> <p class="tag">Hnefatafl was played across the Norse world for centuries before chess arrived. Every piece moves like a rook and is taken by being caught between two enemies. The attackers must capture the king, and the king must reach safety. Play a housecarl, or open a table for a friend and play by turns, by Copenhagen rules on the big board or as Tablut, the older game Linnaeus wrote down in 1732.</p>
<p class="links"><a href="/guide">how to play</a> · <a href="/rules">the rules</a> · <a class="about-link" href="#about" onclick={() => (aboutOpen = true)}>about this game — a labor of love</a> · <button type="button" class="link" onclick={() => (prefsOpen = true)}>preferences</button></p> <p class="links"><a href="/guide">how to play</a> · <a href="/rules">the rules</a> · <a class="about-link" href="#about" onclick={() => (aboutOpen = true)}>about this game</a> · <button type="button" class="link" onclick={() => (prefsOpen = true)}>preferences</button></p>
<Preferences bind:open={prefsOpen} /> <Preferences bind:open={prefsOpen} />
</div> </div>
@@ -231,7 +231,7 @@
<button type="submit" class="quiet" disabled={!ready || code.trim().length < 4}>Join</button> <button type="submit" class="quiet" disabled={!ready || code.trim().length < 4}>Join</button>
</form> </form>
</div> </div>
<p class="muted small">A code opens the door either way: take a seat if one is free, or watch from the Peanut Gallery.</p> <p class="muted small">With a code you can take a seat if one is free, or watch from the Peanut Gallery.</p>
<form class="joinform" onsubmit={claim}> <form class="joinform" onsubmit={claim}>
<span class="or">or bring a seat from another device</span> <span class="or">or bring a seat from another device</span>
<input type="text" bind:value={phrase} placeholder="the four-word phrase" autocomplete="off" aria-label="transfer phrase" /> <input type="text" bind:value={phrase} placeholder="the four-word phrase" autocomplete="off" aria-label="transfer phrase" />
@@ -293,9 +293,9 @@
<!-- The about panel, a tab at a time: its sections are written here, in the game's own words. --> <!-- The about panel, a tab at a time: its sections are written here, in the game's own words. -->
{#snippet aboutGame()} {#snippet aboutGame()}
<div class="about-body"> <div class="about-body">
<p>Hnefatafl is the tafl game of the Vikings, carried by them from Scandinavia to Britain, Ireland, Iceland and beyond, and played until chess arrived in the eleventh and twelfth centuries. No rules from that age survive; the game was reconstructed in modern times from a Sámi cousin, Tablut, whose rules the botanist Carl Linnaeus jotted down on his journey through Lapland in 1732.</p> <p>Hnefatafl is the tafl game of the Vikings, carried by them from Scandinavia to Britain, Ireland, Iceland and beyond, and played until chess arrived in the eleventh and twelfth centuries. No rules from that age survive. The game was reconstructed in modern times from a Sámi cousin, Tablut, whose rules the botanist Carl Linnaeus jotted down on his journey through Lapland in 1732.</p>
<p>This table plays Copenhagen, the modern tournament ruleset, on the eleven-by-eleven board, and Tablut on the nine-by-nine one, with the older board showing its age. The rules it follows are on the <a href="/rules">rules page</a>. The game is in the public domain; the board and pieces here are drawn, not borrowed.</p> <p>This table plays Copenhagen, the modern tournament ruleset, on the eleven-by-eleven board, and Tablut on the nine-by-nine one, with the older board showing its age. The rules it follows are on the <a href="/rules">rules page</a>. The game is in the public domain, and the board and pieces here were drawn for this site.</p>
<p>It is free and keeps no accounts. A game between people lives on a small server as an append-only ledger of moves, so it can be replayed from its first move, and each player is shown only what the rules let them see.</p> <p>It is free and keeps no accounts. A game between people lives on a small server as an append-only ledger of moves, so it can be replayed from its first move.</p>
</div> </div>
{/snippet} {/snippet}
{#snippet aboutTally()} {#snippet aboutTally()}
@@ -315,15 +315,15 @@
</ul> </ul>
{/if} {/if}
<p class="hosting"> <p class="hosting">
The games of Kestrel's Hall are free and will stay free. They run on small servers that cost a few dollars a month; anyone who wants to chip in toward the hosting can at The games of Kestrel's Hall are free and will stay free. They run on small servers that cost a few dollars a month, and anyone who wants to chip in toward the hosting can do so at
<a href="https://ko-fi.com/kestrelsnest" target="_blank" rel="noreferrer">ko-fi.com/kestrelsnest</a>. Nothing is unlocked by it and nothing is withheld without it. <a href="https://ko-fi.com/kestrelsnest" target="_blank" rel="noreferrer">ko-fi.com/kestrelsnest</a>. Every game stays whole either way.
</p> </p>
<p class="made">Hnefatafl belongs to everyone; it is a thousand years old.</p> <p class="made">Hnefatafl belongs to everyone. It is more than a thousand years old.</p>
</div> </div>
{/snippet} {/snippet}
{#snippet aboutWord()} {#snippet aboutWord()}
<div class="about-body"> <div class="about-body">
<p>A rule read wrong, a bug, a game you would like to tell of: write to <a href="mailto:eric@ericwagoner.com">eric@ericwagoner.com</a>, <a href="https://bsky.app/profile/kestrelsnest.social" target="_blank" rel="noreferrer">@kestrelsnest.social</a> on Bluesky, or <a href="https://toots.kestrelsnest.social/@eric" target="_blank" rel="noreferrer">@eric@toots.kestrelsnest.social</a> on Mastodon. The keeper of this hall roosts at <a href="https://kestrelsnest.social" target="_blank" rel="noreferrer">kestrelsnest.social</a>.</p> <p>If a rule reads wrong, something breaks, or you have a game to tell of, write to <a href="mailto:eric@ericwagoner.com">eric@ericwagoner.com</a>, <a href="https://bsky.app/profile/kestrelsnest.social" target="_blank" rel="noreferrer">@kestrelsnest.social</a> on Bluesky, or <a href="https://toots.kestrelsnest.social/@eric" target="_blank" rel="noreferrer">@eric@toots.kestrelsnest.social</a> on Mastodon. The keeper of this hall roosts at <a href="https://kestrelsnest.social" target="_blank" rel="noreferrer">kestrelsnest.social</a>.</p>
</div> </div>
{/snippet} {/snippet}
<About bind:open={aboutOpen} title="About Hnefatafl" tabs={[{ id: 'game', label: 'The game', body: aboutGame }, { id: 'tally', label: 'The tally', body: aboutTally }, { id: 'family', label: 'More games', body: aboutFamily }, { id: 'word', label: 'Send word', body: aboutWord }]} /> <About bind:open={aboutOpen} title="About Hnefatafl" tabs={[{ id: 'game', label: 'The game', body: aboutGame }, { id: 'tally', label: 'The tally', body: aboutTally }, { id: 'family', label: 'More games', body: aboutFamily }, { id: 'word', label: 'Send word', body: aboutWord }]} />
+3 -3
View File
@@ -35,7 +35,7 @@
{#if room.seatEmpty} {#if room.seatEmpty}
<p>{hostName} is gathering players. Sit down above, or watch from the gallery until the game begins.</p> <p>{hostName} is gathering players. Sit down above, or watch from the gallery until the game begins.</p>
{:else} {:else}
<p>The table is full. You watch from the Peanut Gallery; the game begins when {hostName} says.</p> <p>The table is full, so you watch from the Peanut Gallery. The game begins when {hostName} says.</p>
{/if} {/if}
{:else} {:else}
<p class="eyebrow">room {v.roomId}</p> <p class="eyebrow">room {v.roomId}</p>
@@ -60,7 +60,7 @@
<li class="empty muted">{v.size - v.seats.length - v.expected.length} of {v.size} seats empty{#if v.audience > 0}; {v.audience} in the gallery{v.galleryTalk ? ', allowed to talk' : ''}{/if}</li> <li class="empty muted">{v.size - v.seats.length - v.expected.length} of {v.size} seats empty{#if v.audience > 0}; {v.audience} in the gallery{v.galleryTalk ? ', allowed to talk' : ''}{/if}</li>
</ul> </ul>
{#if v.rematchOf} {#if v.rematchOf}
<p class="muted">A rematch of table {v.rematchOf}: the same company, seats held for those not yet back.</p> <p class="muted">This is a rematch of table {v.rematchOf}, with seats held for those not yet back.</p>
{/if} {/if}
{#if !room.spectating} {#if !room.spectating}
<div class="ways"> <div class="ways">
@@ -86,7 +86,7 @@
<p class="muted small note">{v.keeper} keeps this site and answers every call, sometimes within the minute, sometimes after a night's sleep.{#if keeperHour}&nbsp;It is {keeperHour} where {v.keeper} lives.{/if} The seat is held either way.</p> <p class="muted small note">{v.keeper} keeps this site and answers every call, sometimes within the minute, sometimes after a night's sleep.{#if keeperHour}&nbsp;It is {keeperHour} where {v.keeper} lives.{/if} The seat is held either way.</p>
</div> </div>
{:else if v.challenge} {:else if v.challenge}
<p class="muted small note">{v.keeper} has been called to the table by {room.nameOf(v.challenge.by)}.{#if keeperHour}&nbsp;It is {keeperHour} there.{/if} A seat is held: if they can come now they will take it; if they are asleep or away they will leave a word below when they can. Meanwhile the table is yours: seat a housecarl, invite a friend, or open another game in a new tab and play on. This table keeps its place in your hall until you come back.</p> <p class="muted small note">{v.keeper} has been called to the table by {room.nameOf(v.challenge.by)}.{#if keeperHour}&nbsp;It is {keeperHour} there.{/if} A seat is held for them. If they can come now, they will take it. If they are asleep or away, they will leave a word below when they can. In the meantime you can seat a housecarl, invite a friend, or play another game in a new tab. This table keeps its place in your hall until you come back.</p>
{/if} {/if}
{/if} {/if}
{#if room.error}<p class="warning">{room.error}</p>{/if} {#if room.error}<p class="warning">{room.error}</p>{/if}
+3 -3
View File
@@ -59,7 +59,7 @@
<form class="slip" aria-labelledby="report-heading" onsubmit={send}> <form class="slip" aria-labelledby="report-heading" onsubmit={send}>
<h2 id="report-heading">Something amiss?</h2> <h2 id="report-heading">Something amiss?</h2>
{#if sent} {#if sent}
<p class="thanks">Recorded beside the room's ledger, with the round. Thank you; the keeper will study the moment.{#if error} {error}{/if}</p> <p class="thanks">Recorded beside the room's ledger, with the turn. Thank you. The keeper will look into it.{#if error} {error}{/if}</p>
{:else} {:else}
<label class="field"> <label class="field">
<span>What happened?</span> <span>What happened?</span>
@@ -67,14 +67,14 @@
</label> </label>
<label class="field"> <label class="field">
<span>What did you expect?</span> <span>What did you expect?</span>
<textarea bind:value={expected} rows="2" maxlength="2000" placeholder="e.g. a point for me"></textarea> <textarea bind:value={expected} rows="2" maxlength="2000" placeholder="e.g. the defender on e5 taken"></textarea>
</label> </label>
<label class="field picture"> <label class="field picture">
<span>A screenshot, if you have one</span> <span>A screenshot, if you have one</span>
<input type="file" accept="image/png,image/jpeg,image/webp" onchange={pickImage} /> <input type="file" accept="image/png,image/jpeg,image/webp" onchange={pickImage} />
{#if preview}<img class="preview" src={preview} alt="The screenshot you chose" />{/if} {#if preview}<img class="preview" src={preview} alt="The screenshot you chose" />{/if}
</label> </label>
<p class="muted small note">The room code and the round ride along; the keeper can replay the game to this moment.</p> <p class="muted small note">The room code and the turn are sent with it, so the keeper can replay the game to this moment.</p>
{#if error}<p class="warning">{error}</p>{/if} {#if error}<p class="warning">{error}</p>{/if}
<div class="actions"> <div class="actions">
<button type="submit" class="commit small" disabled={!happened.trim() || busy}>{busy ? 'Sending' : 'Send it'}</button> <button type="submit" class="commit small" disabled={!happened.trim() || busy}>{busy ? 'Sending' : 'Send it'}</button>
+1 -1
View File
@@ -57,7 +57,7 @@
<button type="submit" class="quiet" disabled={!draft.trim() || !galleryName.trim() || sending}>Say</button> <button type="submit" class="quiet" disabled={!draft.trim() || !galleryName.trim() || sending}>Say</button>
</form> </form>
{:else if room.spectating} {:else if room.spectating}
<p class="muted small note">The gallery listens; the host has not let it talk.</p> <p class="muted small note">The host has not let the gallery talk at this table.</p>
{:else} {:else}
<form onsubmit={say}> <form onsubmit={say}>
<input type="text" bind:value={draft} maxlength="300" placeholder="Say something to the table" aria-label="Say something to the table" autocomplete="off" /> <input type="text" bind:value={draft} maxlength="300" placeholder="Say something to the table" aria-label="Say something to the table" autocomplete="off" />
+2 -2
View File
@@ -46,7 +46,7 @@ export interface State {
const SIDES: { value: Side; label: string; note: string }[] = [ const SIDES: { value: Side; label: string; note: string }[] = [
{ value: 'defenders', label: 'the defenders, with the king', note: 'Fewer pieces, and the king must reach safety before the ring closes.' }, { value: 'defenders', label: 'the defenders, with the king', note: 'Fewer pieces, and the king must reach safety before the ring closes.' },
{ value: 'attackers', label: 'the attackers', note: 'Twice the pieces, and the first move; close every road and take the king.' } { value: 'attackers', label: 'the attackers', note: 'Twice the pieces and the first move. Close every road and take the king.' }
]; ];
/** The sentences a game ends on. The tally counts finished games by them, so they are written here and nowhere else. */ /** The sentences a game ends on. The tally counts finished games by them, so they are written here and nowhere else. */
@@ -208,7 +208,7 @@ export const game: GameSpec<State, Input> = {
label: 'Rules', label: 'Rules',
choices: [ choices: [
{ value: 'tablut', label: 'Tablut, 9 by 9, after Linnaeus', note: 'The older game. The king escapes to any edge square, and away from the throne two attackers take him like any piece.' }, { value: 'tablut', label: 'Tablut, 9 by 9, after Linnaeus', note: 'The older game. The king escapes to any edge square, and away from the throne two attackers take him like any piece.' },
{ value: 'copenhagen', label: 'Copenhagen, 11 by 11', note: 'The modern tournament game. The king escapes to a corner and falls only to four attackers, three beside the throne.' } { value: 'copenhagen', label: 'Copenhagen, 11 by 11', note: 'The modern tournament game. The king escapes to a corner and falls only to four attackers, or three beside the throne.' }
], ],
default: DEFAULT_SET default: DEFAULT_SET
}, },
+14 -13
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
// How to play: a walk through the page, from the hall to a first game. // How to play: the screen, from the hall to a first game.
import { page } from '$app/state'; import { page } from '$app/state';
/** Opened from a table, the page offers the way back to it and carries it to its cross-links. */ /** Opened from a table, the page offers the way back to it and carries it to its cross-links. */
@@ -15,9 +15,9 @@
<header> <header>
{#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/rules')}>The rules</a> {#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/rules')}>The rules</a>
<h1>How to play</h1> <h1>How to play</h1>
<p class="lede">A walk through the page, from the hall to a first game. The game's own rules are on <a href={withRoom('/rules')}>the rules page</a>.</p> <p class="lede">You hold one side of a Viking battle. The defenders guard a king who wants to slip out to safety, and the attackers ring them round and try to take him. This guide goes through the screen from the hall to your first game. The game's own rules are on <a href={withRoom('/rules')}>the rules page</a>.</p>
<nav> <nav>
<a href="#hall">The hall</a> · <a href="#table">The table</a> · <a href="#board">The board</a> · <a href="#capture">A capture</a> · <a href="#gallery">The Peanut Gallery and table talk</a> · <a href="#hall">The hall</a> · <a href="#table">The table</a> · <a href="#board">The board</a> · <a href="#capture">How a capture works</a> · <a href="#gallery">The Peanut Gallery and table talk</a> ·
<a href="#first">A first game</a> <a href="#first">A first game</a>
</nav> </nav>
</header> </header>
@@ -25,7 +25,7 @@
<section id="hall"> <section id="hall">
<h2>The hall</h2> <h2>The hall</h2>
<p> <p>
Give your name and choose the rules: <em>Copenhagen</em>, the balanced modern game on the big board, or <em>Tablut</em>, the smaller and older one. Choose which side you play. Give your name and choose the rules. <em>Copenhagen</em> is the balanced modern game on the big board, and <em>Tablut</em> is the smaller and older one. Then choose which side you play.
<em>Play now against a housecarl</em> seats a housecarl opposite you and begins. <em>Open a table</em> gives you a four-letter code and a link for a friend. The tables this browser <em>Play now against a housecarl</em> seats a housecarl opposite you and begins. <em>Open a table</em> gives you a four-letter code and a link for a friend. The tables this browser
holds a seat at are listed below, with whose move it is. holds a seat at are listed below, with whose move it is.
</p> </p>
@@ -42,9 +42,10 @@
<section id="board"> <section id="board">
<h2>The board</h2> <h2>The board</h2>
<p> <p>
Tap one of your pieces and its reachable squares light up; tap a square to move there. The last move is shaded, a square a piece was just taken from shows red until the next The attackers are the dark pieces, and they move first. The defenders are the pale pieces around the crowned king on the throne. Tap one of your pieces and the squares it
move, and the strip above the board says whose move it is and what your side is for. The record beside the board lists the moves; click one to see it on the board. The attackers are the dark pieces and move first; the defenders are the pale pieces around the crowned king on the throne. In Copenhagen the four corners are marked: can reach light up, then tap one of those squares to move there. The last move is shaded, and a square a piece was just taken from shows red until the next move. The strip
only the king may enter them, and reaching one wins. In Tablut the board is older and plainer, and the king needs only the edge. above the board says whose move it is and what your side is trying to do. The record beside the board lists the moves, and clicking one shows it on the board. In Copenhagen
the four corners are marked. Only the king may enter them, and reaching one wins. In Tablut the board is older and plainer, and the king needs only to reach the edge.
</p> </p>
</section> </section>
@@ -59,7 +60,7 @@
<circle cx="75" cy="15" r="9" fill="#2a2320" stroke="#0d0a08" stroke-width="1.2" /> <circle cx="75" cy="15" r="9" fill="#2a2320" stroke="#0d0a08" stroke-width="1.2" />
<path d="M62 4 h11 l-3 -3 m3 3 l-3 3" fill="none" stroke="#9cd0dc" stroke-width="1.4" /> <path d="M62 4 h11 l-3 -3 m3 3 l-3 3" fill="none" stroke="#9cd0dc" stroke-width="1.4" />
</svg> </svg>
<figcaption>The right-hand attacker arrives; the pale defender is caught between two enemies and is taken. Only the mover captures: a piece may step into that gap safely on its own turn.</figcaption> <figcaption>The right-hand attacker arrives, and the pale defender, caught between two enemies, is taken. Only the piece that moves makes a capture, so a piece can step into such a gap on its own turn and stay safe.</figcaption>
</figure> </figure>
</section> </section>
@@ -67,7 +68,7 @@
<h2>The Peanut Gallery and table talk</h2> <h2>The Peanut Gallery and table talk</h2>
<p> <p>
A room's link is an invitation to sit while the table is laid and to watch once the game has begun. Anyone who opens it without a seat takes a place in the Peanut Gallery. A room's link is an invitation to sit while the table is laid and to watch once the game has begun. Anyone who opens it without a seat takes a place in the Peanut Gallery.
<em>Table talk</em> is for the players seated, unless the host lets the gallery talk; then a watcher signs a name and their lines are marked as the gallery's. Nothing in <em>Table talk</em> is for the players seated, unless the host lets the gallery talk. Then a watcher gives a name, and their lines are marked as the gallery's. Nothing in
hnefatafl is hidden, so the gallery sees the whole board. hnefatafl is hidden, so the gallery sees the whole board.
</p> </p>
</section> </section>
@@ -75,13 +76,13 @@
<section id="first"> <section id="first">
<h2>A first game</h2> <h2>A first game</h2>
<p> <p>
Play the defenders first. The king wants an open row or column to a corner; the attackers want to close every road while they close in. Pieces are taken by being sandwiched, Play the defenders first. The king wants an open row or column to a corner, and the attackers want to block every road while they close in. In Copenhagen, keep the king off
never by moving between two enemies yourself, so a piece can step into a gap safely. Keep the king off the edge in Copenhagen until a corner is in reach, and remember that the the edge until a corner is in reach. The attackers cannot take him against the edge, though, and a king on the edge, walled in by his own pieces with a move still to make,
attackers cannot take him against the edge: a king on the edge with his pieces around him is a fort. wins the game as an edge fort.
</p> </p>
</section> </section>
<p class="word">Something on this page behave unexpectedly? The <em>Report</em> button in a room's masthead tells the keeper, pinned to the moment.</p> <p class="word">If something behaves unexpectedly, the <em>Report</em> button in a room's masthead tells the keeper, along with the moment it happened.</p>
</main> </main>
<style> <style>
+2 -2
View File
@@ -150,7 +150,7 @@
<a href={`/join/${room.view.rematch.to}`}>Take your seat</a> <a href={`/join/${room.view.rematch.to}`}>Take your seat</a>
{:else} {:else}
<button type="button" class="quiet" disabled={rematching} onclick={rematch}>Rematch with this table</button> <button type="button" class="quiet" disabled={rematching} onclick={rematch}>Rematch with this table</button>
<span>the same company, at a new table; seats are held for everyone here.</span> <span>The same company sits down at a new table, with a seat held for everyone here.</span>
{/if} {/if}
</p> </p>
{/if} {/if}
@@ -159,7 +159,7 @@
<section class="seat"> <section class="seat">
<p class="eyebrow">room {roomId}</p> <p class="eyebrow">room {roomId}</p>
<h2>Take a seat</h2> <h2>Take a seat</h2>
<p>A player has opened this table and is gathering company. Choose a name and sit; the game begins when the host says.</p> <p>A player has opened this table and is gathering company. Choose a name and sit down. The game begins when the host says.</p>
<form class="sit" onsubmit={takeSeat}> <form class="sit" onsubmit={takeSeat}>
<label class="field"> <label class="field">
<span>Your name</span> <span>Your name</span>
+16 -16
View File
@@ -17,10 +17,10 @@
{#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/guide')}>How to play</a> {#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/guide')}>How to play</a>
<h1>The rules</h1> <h1>The rules</h1>
<p class="lede"> <p class="lede">
Hnefatafl is the tafl family's best-known member: a Viking board game played across Scandinavia and the North Atlantic from the fourth century until chess displaced it. No Hnefatafl is the best-known member of the tafl family, a Viking board game played across Scandinavia and the North Atlantic from the fourth century until chess displaced it. No
medieval rules survive. This table plays <em>Copenhagen</em>, the ruleset settled by the Copenhagen Hnefatafl Club in 2012 and used for tournament play since, on the medieval rules survive. This table plays <em>Copenhagen</em>, the ruleset settled by the Copenhagen Hnefatafl Club in 2012 and used for tournament play since, on the
eleven-by-eleven board. It also offers <em>Tablut</em>, the nine-by-nine Sámi game whose rules Carl Linnaeus wrote down in his Lapland journal in 1732: the only version of eleven-by-eleven board. It also offers <em>Tablut</em>, the nine-by-nine Sámi game whose rules Carl Linnaeus wrote down in his Lapland journal in 1732. Tablut is the only
the game with a historical rules text, gaps and all. version of the game with a historical rules text, gaps and all.
</p> </p>
</header> </header>
@@ -36,8 +36,8 @@
<h2>Moving</h2> <h2>Moving</h2>
<p> <p>
Every piece moves like a rook in chess: any number of empty squares along a row or column, never diagonally, never over another piece. Only the king may stop on the throne, and Every piece moves like a rook in chess: any number of empty squares along a row or column, never diagonally, never over another piece. Only the king may stop on the throne, and
in Copenhagen only the king may enter the four marked corners; in Tablut the corners are ordinary squares. In Copenhagen an ordinary piece may pass across the empty throne; in Copenhagen only the king may enter the four marked corners. In Tablut the corners are ordinary squares. In Copenhagen an ordinary piece may pass across the empty throne,
in Tablut it may not. and in Tablut it may not.
</p> </p>
</section> </section>
@@ -45,16 +45,16 @@
<h2>Capturing</h2> <h2>Capturing</h2>
<p> <p>
A piece is captured when the moving piece closes it between itself and another enemy piece on the opposite side, along a row or column. A piece may safely move between two A piece is captured when the moving piece closes it between itself and another enemy piece on the opposite side, along a row or column. A piece may safely move between two
enemies: only the mover captures. The empty throne stands in for an enemy piece, and in Copenhagen so do the four marked corners, so a piece pinned against one of them by a single enemy is taken. The enemies, because only the moving side captures. The empty throne stands in for an enemy piece, and in Copenhagen so do the four marked corners, so a piece pinned against one of them by a single enemy is taken. The
king takes part in captures like any piece. king takes part in captures like any piece.
</p> </p>
<p> <p>
<strong>The king</strong> is harder to take. In Copenhagen he falls only when surrounded on all four sides by attackers, or on three sides with the empty throne as the <strong>The king</strong> is harder to take. In Copenhagen he falls only when surrounded on all four sides by attackers, or on three sides with the empty throne as the
fourth; on the throne itself he needs all four. He cannot be captured against the edge of the board. In Tablut, away from the throne he is taken between two attackers like fourth. On the throne itself he needs all four. He cannot be captured against the edge of the board. In Tablut, away from the throne he is taken between two attackers like
any piece; on the throne he needs four, and beside it three with the throne as the fourth. any piece. On the throne he needs four, and beside it three with the throne as the fourth.
</p> </p>
<p> <p>
<strong>Shieldwall</strong> (Copenhagen only): two or more pieces standing along the edge are captured together when the moving piece closes the row at one end, an enemy or a <strong>Shieldwall</strong> (Copenhagen only). Two or more pieces standing along the edge are captured together when the moving piece closes the row at one end, an enemy or a
corner closes the other, and each piece in the row has an enemy directly in front of it. The king standing in such a row is not taken, but the pieces beside him are. corner closes the other, and each piece in the row has an enemy directly in front of it. The king standing in such a row is not taken, but the pieces beside him are.
</p> </p>
</section> </section>
@@ -62,25 +62,25 @@
<section id="winning"> <section id="winning">
<h2>Winning</h2> <h2>Winning</h2>
<ul> <ul>
<li>The king reaches a corner (Copenhagen) or the edge (Tablut): the defenders win.</li> <li>The defenders win when the king reaches a corner (Copenhagen) or the edge (Tablut).</li>
<li>The king is captured: the attackers win.</li> <li>The attackers win when the king is captured.</li>
<li> <li>
<strong>Edge fort</strong> (Copenhagen): the king stands on the edge, walled in by his own pieces so that no attacker can reach him, and still has a move. The defenders <strong>Edge fort</strong> (Copenhagen). The king stands on the edge, walled in by his own pieces so that no attacker can reach him, and still has a move. The defenders
win. win.
</li> </li>
<li> <li>
<strong>Encirclement</strong> (Copenhagen): the attackers have closed a ring around every remaining defender and the king, so that none of them can ever reach an edge. The <strong>Encirclement</strong> (Copenhagen). The attackers have closed a ring around every remaining defender and the king, so that none of them can ever reach an edge. The
attackers win. attackers win.
</li> </li>
<li>A side with no legal move loses.</li> <li>A side with no legal move loses.</li>
<li>Perpetual repetition is forbidden: when a position stands for the third time, the defenders lose.</li> <li>Perpetual repetition is forbidden. When a position stands for the third time, the defenders lose.</li>
</ul> </ul>
</section> </section>
<section id="tablut"> <section id="tablut">
<h2>Tablut, after Linnaeus</h2> <h2>Tablut, after Linnaeus</h2>
<p> <p>
Linnaeus's notes are in Latin, incomplete, and were mistranslated for two centuries; the confusion produced the edge-escape and corner-escape families of modern hnefatafl. Linnaeus's notes are in Latin, incomplete, and were mistranslated for two centuries.
This table follows the reading now common among reconstructions: nine by nine; sixteen attackers, whom Linnaeus called the Muscovites, against eight defenders, the Swedes, This table follows the reading now common among reconstructions: nine by nine; sixteen attackers, whom Linnaeus called the Muscovites, against eight defenders, the Swedes,
and their king; the king escapes by reaching any edge square; no ordinary piece may enter or cross the throne; the empty throne is hostile to both sides; the king is armed; and their king; the king escapes by reaching any edge square; no ordinary piece may enter or cross the throne; the empty throne is hostile to both sides; the king is armed;
and away from the throne the king is captured by two attackers, like any piece. There are no shieldwalls, edge forts or encirclement in Tablut. and away from the throne the king is captured by two attackers, like any piece. There are no shieldwalls, edge forts or encirclement in Tablut.
@@ -117,7 +117,7 @@
</p> </p>
</section> </section>
<p class="word">If this page reads a rule differently from the text it follows, that is a bug: <a href="mailto:eric@ericwagoner.com">send word</a>.</p> <p class="word">If this page reads a rule differently from the text it follows, that is a bug. Please <a href="mailto:eric@ericwagoner.com">send word</a>.</p>
</main> </main>
<style> <style>