Support 2-6 players: the L, the cross, and the 3x2 from the rulebook

Three player counts join the square and the column: 3 players get the
stair/L with the AUTO WARP joining the two openings that face the
concave notch (convex openings pair geometrically — flagged as
interpretation of the diagram's letters); 5 players get the plus/cross
with tip-to-tip wraps and aisle-warp corners; 6 players get the 3x2
rectangle with straight-across wraps. All six verified layouts are
drawn on, so no count repeats a sector. Rooms accept up to six seats;
the lobby copy follows. 122 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 00:08:15 -04:00
co-authored by Claude Fable 5
parent 8d10dfee67
commit 85b40be113
4 changed files with 98 additions and 7 deletions
+63 -2
View File
@@ -15,7 +15,7 @@ import {
import { layoutIds } from "./board";
import { shuffle, nextInt, type RngState } from "./rng";
export const SUPPORTED_PLAYER_COUNTS = [2, 4] as const;
export const SUPPORTED_PLAYER_COUNTS = [2, 3, 4, 5, 6] as const;
export interface SetupResult {
board: AssembledBoard;
@@ -54,6 +54,28 @@ export function setupBoard(playerCount: number, rng: RngState): SetupResult {
return { board, rng: rngN };
}
if (playerCount === 3) {
// The rulebook's stair/L: one sector on the top row (offset right), two
// on the bottom row. The two openings facing the concave notch join via
// the AUTO WARP; the convex openings pair as below (interpretation of
// the diagram's letters — geometrically matched pairs).
const picks = pick(3);
const placements: SectorPlacement[] = [
{ boardId: picks[0]!.id, origin: { x: 5, y: 0 }, rotation: picks[0]!.rotation },
{ boardId: picks[1]!.id, origin: { x: 0, y: 5 }, rotation: picks[1]!.rotation },
{ boardId: picks[2]!.id, origin: { x: 5, y: 5 }, rotation: picks[2]!.rotation },
];
const board = assembleBoard(placements, {
warpPairs: [
[{ sector: 0, side: "W" }, { sector: 1, side: "N" }], // AUTO WARP corner
[{ sector: 0, side: "N" }, { sector: 2, side: "S" }],
[{ sector: 1, side: "W" }, { sector: 2, side: "E" }],
[{ sector: 0, side: "E" }, { sector: 1, side: "S" }],
],
});
return { board, rng: rngN };
}
if (playerCount === 4) {
const picks = pick(4);
const placements: SectorPlacement[] = [
@@ -68,5 +90,44 @@ export function setupBoard(playerCount: number, rng: RngState): SetupResult {
return { board, rng: rngN };
}
throw new Error(`unsupported player count: ${playerCount} (supported: 2, 4)`);
if (playerCount === 5) {
// The plus/cross: four arms around a center. Opposite arm tips wrap to
// each other; the notch-facing side openings warp around the corners.
const picks = pick(5);
const placements: SectorPlacement[] = [
{ boardId: picks[0]!.id, origin: { x: 5, y: 0 }, rotation: picks[0]!.rotation }, // N arm
{ boardId: picks[1]!.id, origin: { x: 0, y: 5 }, rotation: picks[1]!.rotation }, // W arm
{ boardId: picks[2]!.id, origin: { x: 5, y: 5 }, rotation: picks[2]!.rotation }, // center
{ boardId: picks[3]!.id, origin: { x: 10, y: 5 }, rotation: picks[3]!.rotation }, // E arm
{ boardId: picks[4]!.id, origin: { x: 5, y: 10 }, rotation: picks[4]!.rotation }, // S arm
];
const board = assembleBoard(placements, {
warpPairs: [
[{ sector: 0, side: "N" }, { sector: 4, side: "S" }], // tip to tip
[{ sector: 1, side: "W" }, { sector: 3, side: "E" }],
[{ sector: 0, side: "W" }, { sector: 1, side: "N" }], // aisle-warp corners
[{ sector: 0, side: "E" }, { sector: 3, side: "N" }],
[{ sector: 4, side: "W" }, { sector: 1, side: "S" }],
[{ sector: 4, side: "E" }, { sector: 3, side: "S" }],
],
});
return { board, rng: rngN };
}
if (playerCount === 6) {
// 3x2 rectangle: straight-across wrap (the default pairing).
const picks = pick(6);
const placements: SectorPlacement[] = [
{ boardId: picks[0]!.id, origin: { x: 0, y: 0 }, rotation: picks[0]!.rotation },
{ boardId: picks[1]!.id, origin: { x: 5, y: 0 }, rotation: picks[1]!.rotation },
{ boardId: picks[2]!.id, origin: { x: 10, y: 0 }, rotation: picks[2]!.rotation },
{ boardId: picks[3]!.id, origin: { x: 0, y: 5 }, rotation: picks[3]!.rotation },
{ boardId: picks[4]!.id, origin: { x: 5, y: 5 }, rotation: picks[4]!.rotation },
{ boardId: picks[5]!.id, origin: { x: 10, y: 5 }, rotation: picks[5]!.rotation },
];
const board = assembleBoard(placements);
return { board, rng: rngN };
}
throw new Error(`unsupported player count: ${playerCount} (supported: 2-6)`);
}