턴엔진 테스트 및 버그 수정

This commit is contained in:
2026-01-15 13:27:16 +00:00
parent 550910811c
commit 9c1da3a5d5
2 changed files with 31 additions and 38 deletions
+6 -5
View File
@@ -432,20 +432,21 @@ export class InMemoryTurnWorld {
} }
executeGeneralTurn(general: TurnGeneral): Date { executeGeneralTurn(general: TurnGeneral): Date {
const city = this.cities.get(general.cityId); const currentGeneral = this.generals.get(general.id) ?? general;
const nation = general.nationId > 0 ? (this.nations.get(general.nationId) ?? null) : null; const city = this.cities.get(currentGeneral.cityId);
const nation = currentGeneral.nationId > 0 ? (this.nations.get(currentGeneral.nationId) ?? null) : null;
const result = this.generalTurnHandler.execute({ const result = this.generalTurnHandler.execute({
general, general: currentGeneral,
city, city,
nation, nation,
world: this.state, world: this.state,
schedule: this.schedule, schedule: this.schedule,
}); });
const nextTurnAt = result.nextTurnAt ?? getNextTurnAt(general.turnTime, this.schedule); const nextTurnAt = result.nextTurnAt ?? getNextTurnAt(currentGeneral.turnTime, this.schedule);
const nextGeneral = { const nextGeneral = {
...(result.general ?? general), ...(result.general ?? currentGeneral),
turnTime: nextTurnAt, turnTime: nextTurnAt,
}; };
this.generals.set(nextGeneral.id, nextGeneral); this.generals.set(nextGeneral.id, nextGeneral);
@@ -479,36 +479,39 @@ describe('Reserved Turn Execution Integration', () => {
}; };
const initialRows = [ const initialRows = [
// 0
{ generalId: 1, turnIdx: 0, actionCode: 'che_거병', arg: {} }, { generalId: 1, turnIdx: 0, actionCode: 'che_거병', arg: {} },
{ generalId: 2, turnIdx: 0, actionCode: '휴식', arg: {} },
// 1
{ {
generalId: 1, generalId: 1,
turnIdx: 1, turnIdx: 1,
actionCode: 'che_건국', actionCode: 'che_건국',
arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 }, arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 },
}, },
{ generalId: 2, turnIdx: 2, actionCode: '휴식', arg: {} },
{ generalId: 1, turnIdx: 3, actionCode: 'che_이동', arg: { destCityId: 2 } },
{
generalId: 1,
turnIdx: 4,
actionCode: 'che_건국',
arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 },
},
{ generalId: 1, turnIdx: 5, actionCode: 'che_이동', arg: { destCityId: 2 } },
{
generalId: 1,
turnIdx: 6,
actionCode: 'che_건국',
arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 },
},
{ generalId: 2, turnIdx: 0, actionCode: '휴식', arg: {} },
{ generalId: 2, turnIdx: 1, actionCode: 'che_농지개간', arg: {} }, { generalId: 2, turnIdx: 1, actionCode: 'che_농지개간', arg: {} },
// 2
{ generalId: 1, turnIdx: 2, actionCode: '휴식', arg: {} },
{ generalId: 2, turnIdx: 2, actionCode: 'che_임관', arg: { destNationId: 1 } }, { generalId: 2, turnIdx: 2, actionCode: 'che_임관', arg: { destNationId: 1 } },
// 3
{
generalId: 1,
turnIdx: 3,
actionCode: 'che_건국',
arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 },
},
{ generalId: 2, turnIdx: 3, actionCode: 'che_농지개간', arg: {} }, { generalId: 2, turnIdx: 3, actionCode: 'che_농지개간', arg: {} },
// 4
{ generalId: 1, turnIdx: 4, actionCode: 'che_이동', arg: { destCityId: 2 } },
{ generalId: 2, turnIdx: 4, actionCode: '휴식', arg: {} }, { generalId: 2, turnIdx: 4, actionCode: '휴식', arg: {} },
// 5
{
generalId: 1,
turnIdx: 5,
actionCode: 'che_건국',
arg: { nationName: 'NewEmpire', nationType: 'che_def', colorType: 0 },
},
{ generalId: 2, turnIdx: 5, actionCode: 'che_농지개간', arg: {} }, { generalId: 2, turnIdx: 5, actionCode: 'che_농지개간', arg: {} },
{ generalId: 2, turnIdx: 6, actionCode: 'che_농지개간', arg: {} },
]; ];
const mockPrisma = createMockPrisma(initialRows); const mockPrisma = createMockPrisma(initialRows);
@@ -596,7 +599,7 @@ describe('Reserved Turn Execution Integration', () => {
// 내정 실패 // 내정 실패
expect(world.getCityById(1)!.agriculture).toBe(100); expect(world.getCityById(1)!.agriculture).toBe(100);
// Turn 4: 건국(성공) // Turn 4: 이동(성공), 휴식
await processor.run(new Date(mockDate.getTime() + 5 * 10 * 60 * 1000), { await processor.run(new Date(mockDate.getTime() + 5 * 10 * 60 * 1000), {
budgetMs: 1000, budgetMs: 1000,
maxGenerals: 100, maxGenerals: 100,
@@ -604,21 +607,10 @@ describe('Reserved Turn Execution Integration', () => {
}); });
await reservedTurnStore.flushChanges(); await reservedTurnStore.flushChanges();
const nationSucceeded = world.getNationById(gen1Final.nationId)!;
expect(nationSucceeded.level).toBe(1); // Now a Normal Nation
// Turn 5: 이동, 휴식 [장수2 이동]
await processor.run(new Date(mockDate.getTime() + 6 * 10 * 60 * 1000), {
budgetMs: 1000,
maxGenerals: 100,
catchUpCap: 10,
});
await reservedTurnStore.flushChanges();
expect(world.getGeneralById(1)!.cityId).toBe(2); expect(world.getGeneralById(1)!.cityId).toBe(2);
expect(world.getGeneralById(2)!.cityId).toBe(1); expect(world.getGeneralById(2)!.cityId).toBe(2); // 방랑군 이동은 하위 장수도 같이 이동
// Turn 6: 건국(성공), 농지개간(성공) // Turn 5: 건국(성공), 농지개간(성공)
await processor.run(new Date(mockDate.getTime() + 7 * 10 * 60 * 1000), { await processor.run(new Date(mockDate.getTime() + 7 * 10 * 60 * 1000), {
budgetMs: 1000, budgetMs: 1000,
maxGenerals: 100, maxGenerals: 100,
@@ -628,9 +620,9 @@ describe('Reserved Turn Execution Integration', () => {
const gen1ReallyFinal = world.getGeneralById(1)!; const gen1ReallyFinal = world.getGeneralById(1)!;
expect(world.getNationById(gen1ReallyFinal.nationId)!.level).toBeGreaterThan(0); expect(world.getNationById(gen1ReallyFinal.nationId)!.level).toBeGreaterThan(0);
// Gen 2 fails domestic because City 1 is no longer owned by Gen 2's nation (it's still nationId 0)
expect(world.getCityById(1)!.agriculture).toBe(100); expect(world.getCityById(1)!.agriculture).toBe(100);
expect(world.getCityById(1)!.nationId).toBe(0); // City 1 is still unowned expect(world.getCityById(1)!.nationId).toBe(0); // City 1 is still unowned
expect(world.getCityById(2)!.agriculture).toBeGreaterThan(100); // City 2 agric increased
}); });
it('should fail founding with specific constraints', async () => { it('should fail founding with specific constraints', async () => {