Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/shared/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ describe('agent observation and decision schemas', () => {
recipientAgentId: scoreboard[1]!.agentId,
proposerAllianceId: null,
originatingTurn: 1,
expirationTurn: 9,
expirationTurn: 17,
}).success,
).toBe(true);
expect(
Expand Down
5 changes: 2 additions & 3 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export const DEVELOPMENT_WORLD_CONFIG = {
cellCount: 127,
agentCount: 8,
} as const;
export const ALLIANCE_PROPOSAL_DURATION_TURNS = 8;
export const ALLIANCE_COLOR_PALETTE = [
'#0072B2',
'#D55E00',
Expand Down Expand Up @@ -587,12 +586,12 @@ function validateWorldControllers(
});
if (
proposal.expirationTurn !==
proposal.originatingTurn + ALLIANCE_PROPOSAL_DURATION_TURNS
proposal.originatingTurn + world.agents.length * 2
)
context.addIssue({
code: 'custom',
path: ['pendingAllianceProposals', index, 'expirationTurn'],
message: 'Proposal expiration must be exactly one eight-agent round.',
message: 'Proposal expiration must allow two complete roster rounds.',
});
if (
proposal.proposerAllianceId &&
Expand Down
72 changes: 71 additions & 1 deletion packages/world-engine/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,76 @@ describe('wait and deterministic development world', () => {
});

describe('formal alliances', () => {
it.each([
{ agentCount: 8, lifetime: 16 },
{ agentCount: 20, lifetime: 40 },
])(
'gives proposals a $lifetime-turn lifetime for an $agentCount-agent roster',
({ agentCount, lifetime }) => {
const base = toWorldState(
createDevelopmentWorld({ generatedAt: context.now() }),
);
const agents = [...base.agents.values()];
for (let index = agents.length; index < agentCount; index += 1) {
const id = agentIdSchema.parse(
`00000000-0000-4000-8000-${String(index).padStart(12, '0')}`,
);
agents.push({ ...agents[0]!, id, name: `Agent ${index + 1}` });
}
const initial = {
...base,
agents: new Map(agents.map((item) => [item.id, item])),
};
const [proposer, recipient] = agents;

const proposed = applyDiplomacy(
initial,
proposer!.id,
{ type: 'propose-alliance', recipientId: recipient!.id },
1,
context,
);
const proposal = [
...proposed.state.pendingAllianceProposals!.values(),
][0]!;

expect(proposal.expirationTurn).toBe(1 + lifetime);
},
);

it('keeps a proposal open for two scheduled recipient opportunities', () => {
const initial = toWorldState(
createDevelopmentWorld({ generatedAt: context.now() }),
);
const [proposer, recipient] = [...initial.agents.values()];
const proposed = applyDiplomacy(
initial,
proposer!.id,
{ type: 'propose-alliance', recipientId: recipient!.id },
1,
context,
);

const afterFirstOpportunity = expireAllianceProposals(
proposed.state,
2,
context,
);
const afterSecondOpportunity = expireAllianceProposals(
afterFirstOpportunity,
10,
context,
);
expect(afterSecondOpportunity.pendingAllianceProposals?.size).toBe(1);

const expired = expireAllianceProposals(
afterSecondOpportunity,
17,
context,
);
expect(expired.pendingAllianceProposals?.size).toBe(0);
});

it('forms, colors, leaves, dissolves, and expires proposals deterministically', () => {
const initial = toWorldState(
createDevelopmentWorld({ generatedAt: context.now() }),
Expand Down Expand Up @@ -616,7 +686,7 @@ describe('formal alliances', () => {
10,
context,
);
const expired = expireAllianceProposals(laterProposal.state, 18, context);
const expired = expireAllianceProposals(laterProposal.state, 26, context);
expect(expired.pendingAllianceProposals?.size).toBe(0);
expect(expired.events.at(-1)).toMatchObject({
type: 'alliance-proposal-closed',
Expand Down
3 changes: 1 addition & 2 deletions packages/world-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from 'h3-js';
import {
ALLIANCE_COLOR_PALETTE,
ALLIANCE_PROPOSAL_DURATION_TURNS,
DEVELOPMENT_WORLD_CONFIG,
DEFAULT_COMMUNICATION_RANGE_KM,
NEUTRAL_AGENT_COLOR,
Expand Down Expand Up @@ -510,7 +509,7 @@ export function applyDiplomacy(
recipientAgentId: recipient.id,
proposerAllianceId: proposerAlliance?.id ?? null,
originatingTurn: turnNumber,
expirationTurn: turnNumber + ALLIANCE_PROPOSAL_DURATION_TURNS,
expirationTurn: turnNumber + state.agents.size * 2,
};
proposals.set(proposal.id, proposal);
const event: AllianceEvent = {
Expand Down
Loading