Files
Dune/tests/truthtrance-prescience-knowledge.test.ts

87 lines
5.2 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { baseDeck } from '../game/cards';
import { ecazTreacheryCards } from '../game/ecaz-cards';
import { createGame, newPlayer, type Game } from '../game/engine';
import { truthFactAnswer } from '../game/truthtrance';
import {
knowledgeFactAnswer, knowledgeFactText, parseKnowledgeFact, truthKnowledgeOf,
PRESCIENCE_LEADER_NAMES,
} from '../game/truthtrance-knowledge';
function fixture() {
const game = createGame('PRESTEST', newPlayer('a', 'Atreides', 'atreides'));
const target = newPlayer('e', 'Emperor', 'emperor');
const outsider = newPlayer('g', 'Guild', 'guild');
game.players.push(target, outsider);
game.phase = 6;
const shield = baseDeck().find(card => card.name === 'Shield')!;
target.hand.push(shield);
game.battle = {
territory: 'arrakeen', attacker: 'a', defender: 'e', plans: {}, revealed: false,
traitorCalls: {}, prescience: { player: 'a', field: 'weapon', value: shield.id },
} as NonNullable<Game['battle']>;
return { game, owner: game.players[0], target, outsider, shield };
}
void test('Prescience questions validate public faces and normalize their input', () => {
assert.ok(PRESCIENCE_LEADER_NAMES.includes('Hasimir Fenring'));
assert.deepEqual(parseKnowledgeFact({ kind: 'presciencePeek', field: 'leader', name: 'Hasimir Fenring', extra: true }),
{ kind: 'presciencePeek', field: 'leader', name: 'Hasimir Fenring' });
assert.deepEqual(parseKnowledgeFact({ kind: 'presciencePeek', field: 'dial', value: 2.5, extra: true }),
{ kind: 'presciencePeek', field: 'dial', value: 2.5 });
for (const fact of [
{ kind: 'presciencePeek', field: 'leader', name: 'secret' },
{ kind: 'presciencePeek', field: 'weapon', name: 'secret' },
{ kind: 'presciencePeek', field: 'dial', value: -1 },
{ kind: 'presciencePeek', field: 'dial', value: Infinity },
{ kind: 'presciencePeek', field: 'anything', name: 'None' },
]) assert.throws(() => parseKnowledgeFact(fact));
assert.match(knowledgeFactText({ kind: 'presciencePeek', field: 'dial', value: 2.5 }), /dial.*2.5/);
});
void test('only an entitled viewer answers from the answered live battle element', () => {
const { game, owner, target, outsider, shield } = fixture();
const fact = { kind: 'presciencePeek', field: 'weapon', name: shield.name } as const;
const different = { kind: 'presciencePeek', field: 'weapon', name: 'None' } as const;
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf(game, owner)), 'yes');
assert.equal(knowledgeFactAnswer(different, truthKnowledgeOf(game, owner)), 'no');
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf(game, target)), 'yes');
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf(game, outsider)), 'unknown');
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'defense', name: shield.name }, truthKnowledgeOf(game, owner)), 'unknown');
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf({ ...game, phase: 7 }, owner)), 'unknown');
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf({ ...game, battle: null }, owner)), 'unknown');
const pending = { ...game.battle!, prescience: { player: 'a', field: 'weapon' as const } };
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf({ ...game, battle: pending }, owner)), 'unknown');
const canceled = { ...game.battle!, prescience: undefined };
assert.equal(knowledgeFactAnswer(fact, truthKnowledgeOf({ ...game, battle: canceled }, owner)), 'unknown');
});
void test('dial, leader, absent card and suppressed Ecaz card follow visible battle insight', () => {
const { game, owner, target } = fixture();
game.battle!.prescience = { player: 'a', field: 'dial', value: 2.5 };
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'dial', value: 2.5 }, truthKnowledgeOf(game, owner)), 'yes');
game.battle!.prescience = { player: 'a', field: 'leader', value: target.leaders[0].id };
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'leader', name: target.leaders[0].name }, truthKnowledgeOf(game, owner)), 'yes');
game.battle!.prescience = { player: 'a', field: 'defense', value: null };
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'defense', name: 'None' }, truthKnowledgeOf(game, owner)), 'yes');
const harass = ecazTreacheryCards().find(card => card.effect === 'harassWithdraw')!;
target.hand.push(harass);
game.battle!.prescience = { player: 'a', field: 'defense', value: harass.id };
const knowledge = truthKnowledgeOf(game, owner);
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'defense', name: 'None' }, knowledge), 'yes');
assert.equal(knowledgeFactAnswer({ kind: 'presciencePeek', field: 'defense', name: harass.name }, knowledge), 'no');
assert.equal(truthFactAnswer(owner, { kind: 'and', terms: [
{ kind: 'presciencePeek', field: 'defense', name: 'None' }, { kind: 'spice', compare: 'gte', value: 0 },
] }, knowledge), 'yes');
});
void test('non-entitled players never inspect the concealed answer', () => {
const { game, outsider } = fixture();
game.battle!.prescience = {
player: 'a', field: 'weapon',
get value(): never { throw new Error('Unentitled prescience access'); },
};
assert.equal(truthKnowledgeOf(game, outsider).presciencePeek, null);
});