// Aufnahmeseite für die Katalog-Assets: nur das Brett, ein Bot spielt eine echte Partie. // Gesteuert von scripts/capture/record.mjs über window.capture. import '../../src/client/style.css' import {ZONE_NAMES} from '../../src/client/texts.ts' import {BoardView} from '../../src/engine/app/board/BoardView.ts' import {BOTS} from '../../src/engine/core/bots.ts' import {Game} from '../../src/engine/core/Game.ts' import {mulberry32} from '../../src/engine/core/rng.ts' import {dailyBoard, dailyMap} from '../../src/shared/daily.ts' const params = new URLSearchParams(location.search) // Karte von vor dem ersten Spieltag – läuft nie als Tageskarte, verrät also nichts const day = params.get('day') ?? '2026-10-10' const seed = Number(params.get('seed') ?? 1) const view = new BoardView({interactive: true}) const game = new Game(dailyBoard(dailyMap(new Date(`${day}T00:00:00Z`))), { undoLimit: 0, }) view.setBoard(game.board) view.setLandNames(ZONE_NAMES) const host = document.getElementById('board') as HTMLDivElement host.append(view.svg) // Ganze Partie vorab berechnen, damit die Aufnahme nur noch abspielt const moves: {unit: Parameters[0]; cell: number}[] = [] { const sim = game.clone() const rng = mulberry32(seed) while (!sim.isGameOver()) { const m = BOTS.smart(sim, rng) sim.place(m.unit, m.cell) moves.push({unit: m.unit, cell: m.cell}) } } function draw(): void { view.update(game) view.setRulers(game.rulers()) } const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)) /** Einen Zug zeigen: kurz die Vorschau (beanspruchtes Land + Gold), dann setzen */ async function step( i: number, previewMs: number, afterMs: number, ): Promise { const m = moves[i] if (!m) return const p = game.preview(m.unit, m.cell) if (p.ok) { view.setPlacementPreview({ cell: m.cell, unit: m.unit, zoi: p.zoi, label: `${p.net >= 0 ? '+' : '−'}${Math.abs(p.net)}`, owner: 1, tone: p.net > 0 ? 'gain' : p.net < 0 ? 'loss' : 'neutral', }) await sleep(previewMs) } view.setPlacementPreview(null) const r = game.place(m.unit, m.cell) if (r.ok) { const net = r.yield.points - r.cost if (net !== 0) view.floatLabel( m.cell, `${net > 0 ? '+' : '−'}${Math.abs(net)}`, net > 0 ? 'gain' : 'loss', ) } draw() await sleep(afterMs) } declare global { interface Window { capture: { moves: number /** Partie abspielen: firstMoves sofort (für ein aussagekräftiges erstes Bild), dann im Takt */ play( firstMoves: number, previewMs: number, afterMs: number, ): Promise /** Sofort bis Zug n springen (Standbilder) */ jump(n: number): void } } } window.capture = { moves: moves.length, async play(firstMoves, previewMs, afterMs) { for (let i = 0; i < firstMoves; i++) { const m = moves[i] if (m) game.place(m.unit, m.cell) } draw() for (let i = firstMoves; i < moves.length; i++) await step(i, previewMs, afterMs) }, jump(n) { for (let i = game.moves.length; i < Math.min(n, moves.length); i++) { const m = moves[i] if (m) game.place(m.unit, m.cell) } draw() }, } draw()