26 lines
1.4 KiB
TypeScript
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;
|
|
}
|