From 9c1da3a5d5de34d52cc2fd114b54a802f62ae348 Mon Sep 17 00:00:00 2001 From: Hide_D Date: Thu, 15 Jan 2026 13:27:16 +0000 Subject: [PATCH] =?UTF-8?q?=ED=84=B4=EC=97=94=EC=A7=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B0=8F=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/game-engine/src/turn/inMemoryWorld.ts | 11 ++-- .../test/reservedTurnExecution.test.ts | 58 ++++++++----------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/app/game-engine/src/turn/inMemoryWorld.ts b/app/game-engine/src/turn/inMemoryWorld.ts index b208beb..3c606a0 100644 --- a/app/game-engine/src/turn/inMemoryWorld.ts +++ b/app/game-engine/src/turn/inMemoryWorld.ts @@ -432,20 +432,21 @@ export class InMemoryTurnWorld { } executeGeneralTurn(general: TurnGeneral): Date { - const city = this.cities.get(general.cityId); - const nation = general.nationId > 0 ? (this.nations.get(general.nationId) ?? null) : null; + const currentGeneral = this.generals.get(general.id) ?? general; + const city = this.cities.get(currentGeneral.cityId); + const nation = currentGeneral.nationId > 0 ? (this.nations.get(currentGeneral.nationId) ?? null) : null; const result = this.generalTurnHandler.execute({ - general, + general: currentGeneral, city, nation, world: this.state, schedule: this.schedule, }); - const nextTurnAt = result.nextTurnAt ?? getNextTurnAt(general.turnTime, this.schedule); + const nextTurnAt = result.nextTurnAt ?? getNextTurnAt(currentGeneral.turnTime, this.schedule); const nextGeneral = { - ...(result.general ?? general), + ...(result.general ?? currentGeneral), turnTime: nextTurnAt, }; this.generals.set(nextGeneral.id, nextGeneral); diff --git a/app/game-engine/test/reservedTurnExecution.test.ts b/app/game-engine/test/reservedTurnExecution.test.ts index 6ec316d..b40e30d 100644 --- a/app/game-engine/test/reservedTurnExecution.test.ts +++ b/app/game-engine/test/reservedTurnExecution.test.ts @@ -479,36 +479,39 @@ describe('Reserved Turn Execution Integration', () => { }; const initialRows = [ + // 0 { generalId: 1, turnIdx: 0, actionCode: 'che_거병', arg: {} }, + { generalId: 2, turnIdx: 0, actionCode: '휴식', arg: {} }, + // 1 { generalId: 1, turnIdx: 1, actionCode: 'che_건국', 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: {} }, + // 2 + { generalId: 1, turnIdx: 2, actionCode: '휴식', arg: {} }, { 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: {} }, + // 4 + { generalId: 1, turnIdx: 4, actionCode: 'che_이동', arg: { destCityId: 2 } }, { 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: 6, actionCode: 'che_농지개간', arg: {} }, ]; const mockPrisma = createMockPrisma(initialRows); @@ -596,7 +599,7 @@ describe('Reserved Turn Execution Integration', () => { // 내정 실패 expect(world.getCityById(1)!.agriculture).toBe(100); - // Turn 4: 건국(성공) + // Turn 4: 이동(성공), 휴식 await processor.run(new Date(mockDate.getTime() + 5 * 10 * 60 * 1000), { budgetMs: 1000, maxGenerals: 100, @@ -604,21 +607,10 @@ describe('Reserved Turn Execution Integration', () => { }); 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(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), { budgetMs: 1000, maxGenerals: 100, @@ -628,9 +620,9 @@ describe('Reserved Turn Execution Integration', () => { const gen1ReallyFinal = world.getGeneralById(1)!; 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)!.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 () => {