Hashed seat tokens, ledgered inputs, refusable moves, disk-checked codes, host-only bots, and a drift script

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-09-23 12:07:53 -04:00
1 parent ddb18cb08a
commit c934bbe434
12 files changed
+173 -47

No files matched your search

+3 -4
View File
@@ -87,9 +87,8 @@ export const game: GameSpec<State, Input> = {
view: (state, viewer) => (viewer === SPECTATOR ? structuredClone(state) : structuredClone(state)),
// A function of the state alone: the seed, the round and the seat, so a replay draws the same pick.
botInput: (state, seat) => ({ pick: 1 + Math.floor(random(state.rng + state.rounds.length * 7919 + state.seats.indexOf(seat)) * HIGHEST) }),
cleanInput: (raw) => {
const pick = Number((raw as { pick?: unknown })?.pick);
return { pick: Number.isInteger(pick) && pick >= 1 && pick <= HIGHEST ? pick : 1 };
},
cleanInput: (raw) => ({ pick: Number((raw as { pick?: unknown })?.pick) }),
validate: (_state, _seat, input) =>
Number.isInteger(input.pick) && input.pick >= 1 && input.pick <= HIGHEST ? null : `Name a number from 1 to ${HIGHEST}.`,
nameOf: (state, seat) => state.players[seat]?.name ?? seat
};