import assert from 'node:assert/strict'; import test from 'node:test'; import { parseFreeformFactV1 } from '../game/truthtrance-freeform-facts'; import { parseFreeformFactV2 } from '../game/truthtrance-freeform-facts-v2'; import { TRUTH_CARD_NAMES } from '../game/truthtrance-card-names'; void test('freeform v2 preserves each supported v1 form and every canonical named card', () => { for (const text of ['Do you have at least 5 spice?', 'Do you have exactly 0 spice?', 'Do you have at most 23 spice', ...TRUTH_CARD_NAMES.map(name => `Do you have a ${name}?`)]) { assert.ok(parseFreeformFactV1(text), text); assert.deepEqual(parseFreeformFactV2(text), parseFreeformFactV1(text), text); } }); void test('freeform v2 recognizes explicit total physical hand comparisons', () => { for (const [text, compare, value] of [ ['Do you have at least 3 cards in your hand?', 'gte', 3], ['Do you have exactly 1 card in your hand', 'eq', 1], ['DO YOU HAVE AT MOST 0 CARDS IN YOUR HAND?', 'lte', 0], ] as const) assert.deepEqual(parseFreeformFactV2(text), { kind: 'handInventory', category: 'all', compare, value }); assert.equal(parseFreeformFactV2('Do you have exactly 9007199254740992 cards in your hand?'), null); assert.equal(parseFreeformFactV2('Do you have at least 3 cards in your hand for battle?'), null); }); void test('freeform v2 recognizes one explicit AND or OR of v1 current facts', () => { const shield = { kind: 'hand', name: 'Shield' }; const snooper = { kind: 'hand', name: 'Snooper' }; const spice = { kind: 'spice', compare: 'gte', value: 5 }; assert.deepEqual(parseFreeformFactV2('Do you have at least 5 spice and a Shield?'), { kind: 'and', terms: [spice, shield] }); assert.deepEqual(parseFreeformFactV2('Do you have a Shield or a Snooper?'), { kind: 'or', terms: [shield, snooper] }); assert.deepEqual(parseFreeformFactV2('Do you have a Shield AND do you have at least 5 spice?'), { kind: 'and', terms: [shield, spice] }); assert.deepEqual(parseFreeformFactV2(' do\tyou have an ARTILLERY STRIKE or a Shield '), { kind: 'or', terms: [{ kind: 'hand', name: 'Artillery Strike' }, shield] }); }); void test('freeform v2 never guesses at ambiguous, mixed, future or unsupported language', () => { for (const text of [ '', 'Do you have 5 spice?', 'Do you have more than 5 spice?', 'Do you not have a Shield?', 'Do you have a Shield this turn?', 'Will you have at least 5 spice?', 'Do you have a Shield??', 'Do you have a Shield and a Snooper or a Lasgun?', 'Do you have a Shield and (a Snooper or a Lasgun)?', 'Do you have at least 5 spice and will you win?', 'Do you have a Shield or a secret weapon?', 'Do you have at least 3 cards in your hand and a Shield?', 'Do you have at least 5 spice?\nOr a Shield?', 'Do you have a Shield?'.padEnd(501, ' '), ]) assert.equal(parseFreeformFactV2(text), null, text); });