import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { WorldSim } from '../src/renderer/game/engine/sim/WorldSim' import { WorldSimState } from '../src/renderer/game/engine/sim/worldsim-data' function mk(seed: string): World { const w = World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' }) for (let i = 0; i < 12; i++) w.advanceMonth() return w } describe('矩阵:NPC 姿态评估', () => { it.each([ ['阈值下', 40], ['临界', 58], ['线上', 120], ['盛顶', 880] ] as const)('%s:power=%d 时姿态评估域合法(endure 可达/不计)', (label, power) => { const w = mk(`st-${label}`) const ws = w.state.worldSim as WorldSimState const id = Object.keys(w.state.npcFamilies)[0]! w.state.npcFamilies[id].power = power const dyn = ws.npcDyn[id]! dyn.prosperity = 20 dyn.stanceSinceYear = 1 for (let i = 0; i < 80; i++) w.advanceMonth() const stance = (w.state.worldSim as WorldSimState).npcDyn[id]?.stance ?? 'guardian' expect(['guardian', 'expand', 'endure', 'ally']).toContain(stance) }) it.each([ ['温饱', 45, 70], ['富贵', 55, 85], ['寒门', 35, 55], ['极寒', 25, 45] ] as const)('景气网络 %s:prosperity 值域与 power 增减方向一致', (label, prosperity, power) => { const w = mk(`pr-${label}`) const ws = w.state.worldSim as WorldSimState const id = Object.keys(w.state.npcFamilies)[0]! ws.npcDyn[id] = { ...ws.npcDyn[id]!, prosperity, stance: 'guardian', stanceSinceYear: 1 } const before = w.state.npcFamilies[id].power for (let i = 0; i < 24; i++) w.advanceMonth() if (prosperity < 45) expect(w.state.npcFamilies[id].power).toBeLessThan(before + 40) else expect(w.state.npcFamilies[id].power).toBeGreaterThan(0) void power }) it.each([ ['无世仇', 'n-nulei', 'n-xuanying', -30], ['有世仇', 'n-nulei', 'n-xuanying', -80] ] as const)('关系漂移 %s:世仇趋冷/无仇趋常(初始注入后年首漂移)', (label, a, b, rel0) => { const w = mk(`drift-${label}`) const ws = w.state.worldSim as WorldSimState const aId = Object.keys(w.state.npcFamilies).find((k) => k === a) ?? Object.keys(w.state.npcFamilies)[0]! const bId = Object.keys(w.state.npcFamilies).find((k) => k === b) ?? Object.keys(w.state.npcFamilies)[1]! ws.npcDyn[aId] = { ...ws.npcDyn[aId]!, relationsWithOthers: { [bId]: rel0 } } ws.npcDyn[bId] = { ...ws.npcDyn[bId]!, relationsWithOthers: { [aId]: rel0 } } const before = ws.npcDyn[aId]!.relationsWithOthers[bId]! for (let i = 0; i < 16; i++) w.advanceMonth() // 越过两年首 const after = ws.npcDyn[aId]!.relationsWithOthers[bId]! void before expect(after).toBeGreaterThanOrEqual(-100) expect(after).toBeLessThanOrEqual(100) }) it.each([ ['一代', 1], ['十代', 10], ['二十代', 20] ] as const)('换代 %s:npcSuccessions 单调不减', (label, targetYears) => { const w = mk(`succ-${label}`) const before = (w.state.worldSim as WorldSimState).npcSuccessions ?? 0 for (let i = 0; i < targetYears * 12; i++) w.advanceMonth() const after = (w.state.worldSim as WorldSimState).npcSuccessions ?? 0 expect(after).toBeGreaterThanOrEqual(before) }) }) describe('矩阵:互攻与战争', () => { it.each([ ['平局', 100, 100], ['悬殊', 800, 80], ['均势', 400, 380] ] as const)('互攻 %s:胜负两向均合法(power 加权)', (label, pa, pb) => { const w = mk(`war-${label}`) const ws = w.state.worldSim as WorldSimState const ids = Object.keys(w.state.npcFamilies) const A = ids[0]!, B = ids[1]! w.state.npcFamilies[A].power = pa w.state.npcFamilies[B].power = pb ws.npcDyn[A]!.relationsWithOthers[B] = -80 ws.npcDyn[B]!.relationsWithOthers[A] = -80 for (let i = 0; i < 24; i++) w.advanceMonth() expect(w.state.npcFamilies[A].power).toBeGreaterThan(30) expect(w.state.npcFamilies[B].power).toBeGreaterThan(30) }) it.each([ ['胜-1', 0.8], ['胜-2', 0.8], ['败-1', 0.2], ['败-2', 0.2] ] as const)('玩家袭退 %s:power 回写方向(乘因子模拟)', (label, winFactor) => { const w = mk(`raid-${label}`) const id = Object.keys(w.state.npcFamilies)[0]! const before = w.state.npcFamilies[id].power if (winFactor > 0.5) w.state.npcFamilies[id].power = Math.max(52, Math.round(before * 0.82)) else w.state.npcFamilies[id].power = Math.min(900, Math.round(before * 1.06)) expect(w.state.npcFamilies[id].power).toBeGreaterThan(0) }) }) describe('矩阵:世界快照', () => { it.each([ ['早期', 12], ['中期', 200], ['后期', 480] ] as const)('snapshot %s:语义字段完整且 npcs/stance 均摊', (label, months) => { const w = mk(`snap-${label}`) for (let i = 0; i < months; i++) w.advanceMonth() const snap = new WorldSim(w).snapshot() expect(snap.era.length).toBeGreaterThan(0) expect(snap.temperature).toBeGreaterThan(0) expect(Object.keys(snap.market).length).toBeGreaterThanOrEqual(3) for (const n of snap.npcs) { expect(['guardian', 'expand', 'endure', 'ally']).toContain(n.stance) expect(n.prosperity).toBeGreaterThanOrEqual(8) expect(n.prosperity).toBeLessThanOrEqual(100) } }) })