Files
Dune/game/truthtrance-freeform-facts.ts
T
Quintine 8ae275f598
Verify and publish checkpoint container / container (push) Successful in 10m38s
Interpret bounded Truthtrance fact questions
2026-10-29 04:31:15 +11:00

26 lines
1.4 KiB
TypeScript

import { TRUTH_CARD_NAMES } from './truthtrance-card-names';
import type { TruthFact } from './truthtrance';
/**
* Version 1 deliberately recognizes only complete, unambiguous current facts.
* Keep its semantics stable for questions that persist an interpretation.
* The caller must restrict use to fact-scoped questions; this function never
* interprets current-turn commitments or consults private game state.
*/
export function parseFreeformFactV1(text: string): Extract<TruthFact, { kind: 'hand' | 'spice' }> | null {
if (typeof text !== 'string' || text.length > 500) return null;
const input = text.trim();
const spice = /^do[ \t]+you[ \t]+have[ \t]+(at[ \t]+least|exactly|at[ \t]+most)[ \t]+([0-9]+)[ \t]+spice[ \t]*\??$/i.exec(input);
if (spice) {
const value = Number(spice[2]);
if (!Number.isSafeInteger(value) || value < 0) return null;
const relation = spice[1].toLowerCase().replace(/[ \t]+/g, ' ');
return { kind: 'spice', compare: relation === 'at least' ? 'gte' : relation === 'at most' ? 'lte' : 'eq', value };
}
const card = /^do[ \t]+you[ \t]+have[ \t]+(?:a|an)[ \t]+(.+?)[ \t]*\??$/i.exec(input);
if (!card) return null;
const name = card[1].trim().toLowerCase();
const matches = TRUTH_CARD_NAMES.filter(candidate => candidate.toLowerCase() === name);
return matches.length === 1 ? { kind: 'hand', name: matches[0] } : null;
}