Support sector-specific Truthtrance shipments
This commit is contained in:
1 parent
8006e53580
commit
536d334543
27 files changed
+1121
-71
No files matched your search
@@ -0,0 +1,84 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { compileMixedActionExpression, type MixedActionExpression } from '../game/mixed-action-question';
|
||||
import {
|
||||
TurnActionError,
|
||||
parseTurnActionLeaf,
|
||||
recordTurnActionShipment,
|
||||
turnActionBranches,
|
||||
turnActionValue,
|
||||
validateTurnActionPromises,
|
||||
type TurnActionLeaf,
|
||||
type TurnActionPromise,
|
||||
} from '../game/turn-action-promises';
|
||||
|
||||
type Expression = MixedActionExpression<TurnActionLeaf>;
|
||||
const ship = (sector?: number, minimum = 3, territory = 'wind_pass'): Expression => ({
|
||||
kind: 'action', action: { kind: 'ship', territory, minimum, ...(sector === undefined ? {} : { sector }) },
|
||||
});
|
||||
const group = (kind: 'and' | 'or', ...terms: Expression[]): Expression => ({ kind, terms });
|
||||
function promise(mixed: Expression, answer = true): TurnActionPromise {
|
||||
return {
|
||||
turn: 1, mixed, event: 'whole:1', player: 'p', asker: 'a', answer,
|
||||
compiled: compileMixedActionExpression(mixed, () => 'yes', answer),
|
||||
shipment: { pending: true, event: null }, progress: [], payments: [],
|
||||
transportClosed: false, paymentClosed: false, fulfilled: false, released: false,
|
||||
};
|
||||
}
|
||||
|
||||
void test('whole shipment atoms preserve exact printed sectors and reject invalid ones', () => {
|
||||
assert.deepEqual(parseTurnActionLeaf({ kind: 'ship', territory: 'wind_pass', minimum: 3, sector: 15 }),
|
||||
{ kind: 'ship', territory: 'wind_pass', minimum: 3, sector: 15 });
|
||||
for (const input of [
|
||||
{ kind: 'ship', territory: 'wind_pass', minimum: 3, sector: 4 },
|
||||
{ kind: 'ship', territory: 'wind_pass', minimum: 3, sector: 15.5 },
|
||||
{ kind: 'move', territory: 'wind_pass', minimum: 3, sector: 15 },
|
||||
{ kind: 'ship', territory: 'wind_pass', minimum: 3, sector: null },
|
||||
]) assert.throws(() => parseTurnActionLeaf(input), TurnActionError);
|
||||
});
|
||||
|
||||
void test('one actual matching sector fulfills the signed Yes or rejects the signed No', () => {
|
||||
const exact = promise(ship(15));
|
||||
const [done] = recordTurnActionShipment([exact], 'p', 1, { territory: 'wind_pass', sector: 15, amount: 3 });
|
||||
assert.deepEqual(done.shipment.event, { territory: 'wind_pass', sector: 15, amount: 3 });
|
||||
assert.equal(done.fulfilled, true);
|
||||
assert.equal(turnActionValue(done), true);
|
||||
validateTurnActionPromises([done], ['p', 'a']);
|
||||
assert.throws(() => recordTurnActionShipment([promise(ship(15), false)], 'p', 1,
|
||||
{ territory: 'wind_pass', sector: 15, amount: 3 }), TurnActionError);
|
||||
const [other] = recordTurnActionShipment([promise(ship(15), false)], 'p', 1,
|
||||
{ territory: 'wind_pass', sector: 14, amount: 3 });
|
||||
assert.equal(other.fulfilled, true);
|
||||
assert.equal(turnActionValue(other), false);
|
||||
const [unknown] = recordTurnActionShipment([promise(ship(15), false)], 'p', 1,
|
||||
{ territory: 'wind_pass', amount: 3 });
|
||||
assert.equal(turnActionValue(unknown), false);
|
||||
});
|
||||
|
||||
void test('sector and territory-wide atom identity remain distinct across AND and OR', () => {
|
||||
const broad = ship(), exact14 = ship(14), exact15 = ship(15);
|
||||
const alternatives = promise(group('or', broad, exact14));
|
||||
validateTurnActionPromises([alternatives], ['p', 'a']);
|
||||
const branches = [...turnActionBranches(alternatives)];
|
||||
assert.equal(branches.length, 2);
|
||||
assert.ok(branches.some(row => row.some(leaf => leaf.kind === 'ship' && leaf.sector === undefined)));
|
||||
assert.ok(branches.some(row => row.some(leaf => leaf.kind === 'ship' && leaf.sector === 14)));
|
||||
assert.deepEqual([...turnActionBranches(promise(group('and', exact14, exact15)))], []);
|
||||
assert.equal([...turnActionBranches(promise(group('and', broad, exact14)))].length, 1);
|
||||
const [done] = recordTurnActionShipment([alternatives], 'p', 1, { territory: 'wind_pass', sector: 15, amount: 3 });
|
||||
assert.equal(done.fulfilled, true);
|
||||
});
|
||||
|
||||
void test('mixed exact and broad receipts retain one real event without changing legacy bytes', () => {
|
||||
const legacy = promise(ship());
|
||||
const [legacyDone] = recordTurnActionShipment([legacy], 'p', 1, { territory: 'wind_pass', sector: 15, amount: 3 });
|
||||
assert.deepEqual(legacyDone.shipment.event, { territory: 'wind_pass', amount: 3 });
|
||||
assert.equal(JSON.stringify(legacyDone.shipment.event), '{"territory":"wind_pass","amount":3}');
|
||||
validateTurnActionPromises([legacyDone], ['p', 'a']);
|
||||
const row = promise(group('or', ship(), ship(14)));
|
||||
const [done] = recordTurnActionShipment([row], 'p', 1, { territory: 'wind_pass', sector: 15, amount: 3 });
|
||||
assert.deepEqual(done.shipment.event, { territory: 'wind_pass', amount: 3, sector: 15 });
|
||||
validateTurnActionPromises([done], ['p', 'a']);
|
||||
assert.throws(() => recordTurnActionShipment([promise(ship(14))], 'p', 1,
|
||||
{ territory: 'wind_pass', sector: 19, amount: 3 }), TurnActionError);
|
||||
});
|
||||
Reference in new issue
Block a user