Files
Dune/game/truthtrance-freeform-facts-v5.ts
T
Quintine 15a4f3038a
Verify and publish checkpoint container / container (push) Successful in 10m54s
Interpret compound Truthtrance hand facts
2026-10-29 17:56:30 +11:00

39 lines
1.9 KiB
TypeScript

import { parseFreeformFactV3 } from './truthtrance-freeform-facts-v3';
import { parseFreeformFactV4 } from './truthtrance-freeform-facts-v4';
import type { TruthFact } from './truthtrance';
type Compound = Extract<TruthFact, { kind: 'and' | 'or' }>;
/**
* A new, deliberately narrow grammar: two existing current-fact atoms joined
* by one unambiguous AND/OR. Older parser versions and their saved receipts
* remain unchanged. Call only for fact-scoped text and show the interpretation.
*/
export function parseTruthFreeformFactsV5(text: string): Compound | null {
if (typeof text !== 'string' || text.length > 500) return null;
const input = text.trim();
// A complete old interpretation, including a card name containing "and",
// retains its original meaning rather than being reinterpreted by V5.
if (parseFreeformFactV3(input) || parseFreeformFactV4(input)) return null;
const question = /^do[ \t]+you[ \t]+have[ \t]+(.+?)[ \t]*\??$/i.exec(input);
if (!question) return null;
const body = question[1];
const atom = (part: string): TruthFact | null => {
const value = part.trim();
if (!value || /[?\r\n]/.test(value)) return null;
const full = /^do[ \t]+you[ \t]+(?:have|not[ \t]+have)[ \t]+/i.test(value)
? value : /^not[ \t]+have[ \t]+/i.test(value) ? `Do you ${value}`
: /^have[ \t]+/i.test(value) ? `Do you ${value}` : `Do you have ${value}`;
const fact = parseFreeformFactV3(full) ?? parseFreeformFactV4(full);
return fact && fact.kind !== 'and' && fact.kind !== 'or' ? fact : null;
};
const matches: Compound[] = [];
for (const connector of body.matchAll(/[ \t]+(and|or)[ \t]+/gi)) {
const index = connector.index ?? 0;
const left = atom(body.slice(0, index));
const right = atom(body.slice(index + connector[0].length));
if (left && right) matches.push({ kind: connector[1].toLowerCase() as 'and' | 'or', terms: [left, right] });
}
return matches.length === 1 ? matches[0] : null;
}