Add verified Truthtrance hand inventory questions
Players can ask total-hand and primary-role card-count comparisons using the existing count controls and compound facts. Component presentation shares the same default-role classification, including canonical Richese cards, Ix alternate uses, and Ecaz slot-only specials. Only the respondent receives the verified aggregate answer; current facts do not impose future custody promises. Eight new tests cover all 60 catalog cards, real engine actions, malformed input, private worlds, all four bots, JSON continuation, and a legal custody transfer. Expanded production-room SQLite cases cover restored total/category/compound facts, suspended auction state, and one winning concurrent answer/discard. Independent review's two copy issues were fixed before broad verification. Validation: types, lint and 4,200 offline tests passed; production build passed; 40 HTTP tests passed. One stable broad run (check 123036 ms, build 6505 ms, integration 23467 ms). Browser room LC3E55GY verified combined role counts, total hand size, invalid-input feedback and refresh at 390px phone width. All 33 pre-integration rooms preserved unchanged; HTTP checks added 30 rooms. No complete-mode, full-game or publication gate opened. Private report: 20260913-hand-inventory-final/report.json Source fingerprint: c6a69a9e69941cdd1e5734d92afedbf10d31fda36c91d26ca7e15f4fb7c59b18 Efficiency pilot milestone 3: aggregate counter 58,695,053 to 59,144,653 at completed verification = 449,600 tokens, including context/coordination overhead. Two bounded workhorse-model helpers, reused UI and SQLite fixtures, one browser room. Counter is not monetary cost and this differently sized batch does not establish a savings percentage. Final Git/push overhead follows this sample.
This commit is contained in:
1 parent
32791ed5e2
commit
7454456755
14 files changed
+980
-151
No files matched your search
+18
-3
@@ -9,6 +9,12 @@ import {
|
||||
type CardCountFact,
|
||||
} from './truthtrance-card-count';
|
||||
import { richeseCards } from './richese-cards';
|
||||
import {
|
||||
parseHandInventoryFact,
|
||||
handInventoryFactMatches,
|
||||
handInventoryFactText,
|
||||
type HandInventoryFact,
|
||||
} from './truthtrance-hand-inventory';
|
||||
import {
|
||||
parsePlanClaim,
|
||||
planClaimText,
|
||||
@@ -22,6 +28,7 @@ import { DUKE_VIDAL_ID } from './duke-vidal';
|
||||
|
||||
export type TruthFact =
|
||||
| CardCountFact
|
||||
| HandInventoryFact
|
||||
| { kind: 'hand'; name: string }
|
||||
| { kind: 'traitor'; leader: string }
|
||||
| { kind: 'spice'; compare: 'eq' | 'gte' | 'lte'; value: number }
|
||||
@@ -75,9 +82,11 @@ function parseFact(
|
||||
'Truthtrance supports at most 16 clauses and four levels of grouping.',
|
||||
);
|
||||
const v = record(value);
|
||||
if (v.kind === 'handCount') {
|
||||
if (v.kind === 'handCount' || v.kind === 'handInventory') {
|
||||
try {
|
||||
return parseCardCountFact(v, TRUTH_CARD_NAMES);
|
||||
return v.kind === 'handCount'
|
||||
? parseCardCountFact(v, TRUTH_CARD_NAMES)
|
||||
: parseHandInventoryFact(v);
|
||||
} catch (error) {
|
||||
throw new TruthError(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
@@ -146,7 +155,10 @@ function parseQuestion(g: Game, asker: string, value: unknown): TruthQuestion {
|
||||
g.status === 'playing' &&
|
||||
g.phase === 5 &&
|
||||
g.active === v.target &&
|
||||
shipmentAvailable(g,g.players.find((p) => p.id === v.target)!) &&
|
||||
shipmentAvailable(
|
||||
g,
|
||||
g.players.find((p) => p.id === v.target)!,
|
||||
) &&
|
||||
!g.response &&
|
||||
!g.decision &&
|
||||
!g.phaseOpening &&
|
||||
@@ -252,6 +264,8 @@ export function truthFactAnswer(
|
||||
p: Pick<Player, 'hand' | 'traitors' | 'traitorChoices' | 'spice'>,
|
||||
fact: TruthFact,
|
||||
): TruthAnswer {
|
||||
if (fact.kind === 'handInventory')
|
||||
return handInventoryFactMatches(p.hand, fact) ? 'yes' : 'no';
|
||||
if (fact.kind === 'handCount')
|
||||
return cardCountFactMatches(p.hand, fact) ? 'yes' : 'no';
|
||||
if (fact.kind === 'hand')
|
||||
@@ -293,6 +307,7 @@ export function truthQuestionText(
|
||||
if (q.kind === 'battlePlan')
|
||||
return `In this battle in ${territory(q.territory).name}, will it be true that ${planClaimText(q.claim, leaderName)}?`;
|
||||
const clause = (f: TruthFact): string => {
|
||||
if (f.kind === 'handInventory') return handInventoryFactText(f);
|
||||
if (f.kind === 'handCount') return cardCountFactText(f);
|
||||
if (f.kind === 'hand') return `you hold ${f.name}`;
|
||||
if (f.kind === 'traitor') return `${leaderName(f.leader)} is your traitor`;
|
||||
|
||||
Reference in new issue
Block a user