fix(diplomacy): 전쟁 기간을 양방향으로 동기화한다
This commit is contained in:
@@ -92,10 +92,12 @@ export const processDiplomacyMonth = (
|
||||
entry.term = clamp(entry.term + termIncrease, 0, MAX_WAR_TERM);
|
||||
}
|
||||
|
||||
// 전쟁 종료 판정: 양방 term이 1 이하이면 통상으로 전환.
|
||||
// 전쟁은 양방향 diplomacy row로 저장되지만 기간은 하나의 관계가 소유한다.
|
||||
// Ref처럼 방향별 사상자 연장을 먼저 계산하되, 더 긴 기간을 양쪽에 적용하여
|
||||
// 한쪽만 0개월 전쟁으로 남는 비대칭 상태를 다음 월까지 노출하지 않는다.
|
||||
const processedPairs = new Set<string>();
|
||||
for (const entry of next) {
|
||||
if (entry.state !== DIPLOMACY_STATE.WAR || entry.term > 1) {
|
||||
if (entry.state !== DIPLOMACY_STATE.WAR) {
|
||||
continue;
|
||||
}
|
||||
const pairKey = buildDiplomacyKey(
|
||||
@@ -106,12 +108,20 @@ export const processDiplomacyMonth = (
|
||||
continue;
|
||||
}
|
||||
const opposite = byKey.get(buildDiplomacyKey(entry.toNationId, entry.fromNationId));
|
||||
if (opposite && opposite.state === DIPLOMACY_STATE.WAR && opposite.term <= 1) {
|
||||
if (!opposite || opposite.state !== DIPLOMACY_STATE.WAR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sharedTerm = Math.max(entry.term, opposite.term);
|
||||
entry.term = sharedTerm;
|
||||
opposite.term = sharedTerm;
|
||||
processedPairs.add(pairKey);
|
||||
|
||||
if (sharedTerm <= 1) {
|
||||
entry.state = DIPLOMACY_STATE.TRADE;
|
||||
entry.term = 0;
|
||||
opposite.state = DIPLOMACY_STATE.TRADE;
|
||||
opposite.term = 0;
|
||||
processedPairs.add(pairKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,32 @@ describe('diplomacy month processing', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps an asymmetric war on one shared countdown and ends it once', () => {
|
||||
let entries = [buildEntry(1, 2, DIPLOMACY_STATE.WAR, 1), buildEntry(2, 1, DIPLOMACY_STATE.WAR, 3)];
|
||||
const generalCounts = new Map([
|
||||
[1, 1],
|
||||
[2, 1],
|
||||
]);
|
||||
|
||||
entries = processDiplomacyMonth(entries, generalCounts);
|
||||
expect(entries.map(({ state, term }) => ({ state, term }))).toEqual([
|
||||
{ state: DIPLOMACY_STATE.WAR, term: 2 },
|
||||
{ state: DIPLOMACY_STATE.WAR, term: 2 },
|
||||
]);
|
||||
|
||||
entries = processDiplomacyMonth(entries, generalCounts);
|
||||
expect(entries.map(({ state, term }) => ({ state, term }))).toEqual([
|
||||
{ state: DIPLOMACY_STATE.WAR, term: 1 },
|
||||
{ state: DIPLOMACY_STATE.WAR, term: 1 },
|
||||
]);
|
||||
|
||||
entries = processDiplomacyMonth(entries, generalCounts);
|
||||
expect(entries.map(({ state, term }) => ({ state, term }))).toEqual([
|
||||
{ state: DIPLOMACY_STATE.TRADE, term: 0 },
|
||||
{ state: DIPLOMACY_STATE.TRADE, term: 0 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('extends war term based on accumulated casualties', () => {
|
||||
const entries = [buildEntry(1, 2, DIPLOMACY_STATE.WAR, 3, 400), buildEntry(2, 1, DIPLOMACY_STATE.WAR, 3, 0)];
|
||||
const result = processDiplomacyMonth(
|
||||
@@ -75,7 +101,7 @@ describe('diplomacy month processing', () => {
|
||||
const reverse = result.find((entry) => entry.fromNationId === 2 && entry.toNationId === 1);
|
||||
expect(forward?.term).toBe(4);
|
||||
expect(forward?.dead).toBe(0);
|
||||
expect(reverse?.term).toBe(2);
|
||||
expect(reverse?.term).toBe(4);
|
||||
});
|
||||
|
||||
it('expires non-aggression pact into trade', () => {
|
||||
|
||||
Reference in New Issue
Block a user