refactor(logic): 과도한 수치 호환 보정을 제거한다
Core 수치 상태는 JavaScript와 PostgreSQL의 자연 정밀도를 유지한다. 정수 상태 경계와 절삭, 수입 배분 및 사망자 분할 순서는 보존한다.
This commit is contained in:
@@ -5,7 +5,7 @@ import type { City, General, Nation } from '../../src/domain/entities.js';
|
||||
import type { WorldSnapshot } from '../../src/world/types.js';
|
||||
import {
|
||||
commandSpec as procureSpec,
|
||||
roundLegacyAccumulatedInteger,
|
||||
roundAccumulatedInteger,
|
||||
resolveLegacyDedicationLevel,
|
||||
resolveLegacyExperienceLevel,
|
||||
} from '../../src/actions/turn/general/che_물자조달.js';
|
||||
@@ -35,13 +35,9 @@ import {
|
||||
normalizeLegacyGeneratedDex,
|
||||
resolveLegacySpecialityAge,
|
||||
} from '../../src/actions/turn/general/che_인재탐색.js';
|
||||
import {
|
||||
addLegacyStoredTech,
|
||||
readLegacyStoredTech,
|
||||
toLegacyStoredTech,
|
||||
} from '../../src/actions/turn/general/che_기술연구.js';
|
||||
import { readLegacyCityTrust, storeLegacyCityTrust } from '../../src/actions/turn/general/legacyCityTrust.js';
|
||||
import { roundLegacyRecruitCost } from '../../src/actions/turn/general/che_징병.js';
|
||||
import { addTech } from '../../src/actions/turn/general/che_기술연구.js';
|
||||
import { adjustCityTrust, resolveCityTrustValue } from '../../src/actions/turn/general/cityTrust.js';
|
||||
import { roundRecruitCost } from '../../src/actions/turn/general/che_징병.js';
|
||||
import { resolveLegacyDomesticTrust } from '../../src/actions/turn/general/che_상업투자.js';
|
||||
import { traitModule as ambitiousPersonality } from '../../src/actionModules/traits/personality/che_출세.js';
|
||||
|
||||
@@ -54,7 +50,7 @@ describe('General Commands New Scenario', () => {
|
||||
const delta = (45 * 0.7) / 3;
|
||||
expect(delta).toBe(10.499999999999998);
|
||||
expect(Math.round(delta)).toBe(10);
|
||||
expect(roundLegacyAccumulatedInteger(4554, delta)).toBe(4565);
|
||||
expect(roundAccumulatedInteger(4554, delta)).toBe(4565);
|
||||
});
|
||||
|
||||
it('calculates procurement levels before MariaDB rounds the INT columns', () => {
|
||||
@@ -71,32 +67,28 @@ describe('General Commands New Scenario', () => {
|
||||
expect(resolveLegacySpecialityAge(80, 24, 12)).toBe(29);
|
||||
});
|
||||
|
||||
it('stores technology as binary32 without per-update decimal quantization', () => {
|
||||
const value = 433.51797;
|
||||
expect(toLegacyStoredTech(value)).toBe(Math.fround(value));
|
||||
expect(toLegacyStoredTech(value)).not.toBe(Number(Math.fround(value).toPrecision(6)));
|
||||
expect(readLegacyStoredTech(624.0966796875)).toBe(624.097);
|
||||
expect(addLegacyStoredTech(624.0966796875, 22.9)).toBe(Math.fround(624.097 + 22.9));
|
||||
expect(readLegacyStoredTech(533.3125)).toBe(533.312);
|
||||
expect(readLegacyStoredTech(533.4375)).toBe(533.438);
|
||||
it('keeps full precision while accumulating technology', () => {
|
||||
const current = 624.0966796875;
|
||||
const updated = addTech(current, 22.9);
|
||||
|
||||
expect(updated).toBe(current + 22.9);
|
||||
expect(updated).not.toBe(Math.fround(current + 22.9));
|
||||
expect(updated).not.toBe(Number((current + 22.9).toPrecision(6)));
|
||||
});
|
||||
|
||||
it('separates MariaDB FLOAT trust storage from its six-digit PHP read value', () => {
|
||||
const stored = storeLegacyCityTrust(88.306755);
|
||||
it('keeps full precision while adjusting city trust', () => {
|
||||
const current = resolveCityTrustValue(88.306755);
|
||||
|
||||
expect(stored).toBe(Math.fround(88.306755));
|
||||
expect(stored).not.toBe(readLegacyCityTrust(stored));
|
||||
expect(readLegacyCityTrust(stored)).toBe(88.3068);
|
||||
expect(readLegacyCityTrust(storeLegacyCityTrust(readLegacyCityTrust(stored) + 10))).toBe(98.3068);
|
||||
expect(readLegacyCityTrust(storeLegacyCityTrust(93.40625))).toBe(93.4062);
|
||||
expect(adjustCityTrust(current, 10)).toBe(98.306755);
|
||||
expect(adjustCityTrust(current, 20)).toBe(100);
|
||||
expect(adjustCityTrust(current, -100)).toBe(0);
|
||||
});
|
||||
|
||||
it('rounds recruitment cost across the PHP half boundary', () => {
|
||||
it('uses the native integer boundary for recruitment cost', () => {
|
||||
const cavalryCost = (11 * 1.15 * 7000) / 100;
|
||||
|
||||
expect(cavalryCost).toBe(885.4999999999999);
|
||||
expect(Math.round(cavalryCost)).toBe(885);
|
||||
expect(roundLegacyRecruitCost(cavalryCost)).toBe(886);
|
||||
expect(roundRecruitCost(cavalryCost)).toBe(885);
|
||||
});
|
||||
|
||||
it('uses the legacy minimum trust for domestic calculations', () => {
|
||||
|
||||
@@ -278,8 +278,8 @@ describe('war aftermath', () => {
|
||||
messageTime: MESSAGE_TIME,
|
||||
});
|
||||
|
||||
expect(attackerNation.meta.tech).toBe(Math.fround(1000.6));
|
||||
expect(defenderNation.meta.tech).toBe(Math.fround(1000.9));
|
||||
expect(attackerNation.meta.tech).toBe(1000.6);
|
||||
expect(defenderNation.meta.tech).toBe(1000.9);
|
||||
expect(outcome.diplomacyDeltas).toHaveLength(2);
|
||||
expect(attackerCity.meta.dead).toBe(60);
|
||||
expect(defenderCity.meta.dead).toBe(90);
|
||||
|
||||
@@ -293,7 +293,7 @@ describe('war triggers', () => {
|
||||
expect(unit.getComputedAttack()).toBeCloseTo(608, 12);
|
||||
});
|
||||
|
||||
it('normalizes accumulated dexterity to the PHP SQL float precision', () => {
|
||||
it('keeps accumulated dexterity at full precision', () => {
|
||||
const general = buildGeneral(80);
|
||||
general.meta.dex4 = 14_677.199999999997;
|
||||
const wizard = new WarCrewType({
|
||||
@@ -316,7 +316,7 @@ describe('war triggers', () => {
|
||||
|
||||
unit.addDex(wizard, 2047);
|
||||
|
||||
expect(general.meta.dex4).toBe(16_519.5);
|
||||
expect(general.meta.dex4).toBe(16_519.499999999996);
|
||||
});
|
||||
|
||||
it('preserves the legacy fractional morale gain after a win', () => {
|
||||
|
||||
@@ -2,16 +2,21 @@ import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { round } from '../src/war/utils.js';
|
||||
|
||||
describe('legacy war rounding', () => {
|
||||
it('matches PHP round() at drifted positive and negative half boundaries', () => {
|
||||
expect(round(4159.499999999999)).toBe(4160);
|
||||
expect(round(-4159.499999999999)).toBe(-4160);
|
||||
expect(round(8719.4999999999945)).toBe(8720);
|
||||
expect(round(-8719.4999999999945)).toBe(-8720);
|
||||
describe('war rounding', () => {
|
||||
it('uses the native number boundary without half-point correction', () => {
|
||||
expect(round(4159.499999999999)).toBe(4159);
|
||||
expect(round(-4159.499999999999)).toBe(-4159);
|
||||
expect(round(8719.4999999999945)).toBe(8719);
|
||||
expect(round(-8719.4999999999945)).toBe(-8719);
|
||||
});
|
||||
|
||||
it('keeps values meaningfully below a half boundary on the lower integer', () => {
|
||||
expect(round(4159.499999)).toBe(4159);
|
||||
expect(round(-4159.499999)).toBe(-4159);
|
||||
});
|
||||
|
||||
it('uses JavaScript semantics at exact half points', () => {
|
||||
expect(round(1.5)).toBe(2);
|
||||
expect(round(-1.5)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user