Files
core2026/app/game-frontend/test/commandCityDistance.test.ts
T
Hide_DandClaude Opus 5.5 0a9c47eddf 도시 대상 명령 입력에 Ref 거리별 도시 목록 복원
Ref ProcessCity의 `N칸 떨어진 도시:` 목록(CitiesBasedOnDistance)을 전체화면 인자 입력에
되살린다. 이동·출병 1칸, 강행·첩보·화계·탈취·파괴·선동 3칸을 map layout path의 BFS로
Ref searchDistance와 같은 순서로 나열하고, 거리별 magenta/orange/yellow 밑줄 도시를 누르면
대상 도시를 고른다. che 지도 94개 도시 결과를 Ref PHP 원문 실행 fixture와 비교하는 unit test와
1200/390px e2e를 추가한다.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 14:35:40 +00:00

62 lines
2.5 KiB
TypeScript

import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
import { COMMAND_CITY_DISTANCE_RANGE, citiesBasedOnDistance } from '../src/components/command/commandCityDistance.ts';
type MapDefinition = { cities: Array<{ id: number; connections: number[] }> };
const readJson = <T>(path: string): T => JSON.parse(readFileSync(new URL(path, import.meta.url), 'utf8')) as T;
// Ref `hwe/func.php` searchDistance와 `func_legacy.php` JSCitiesBasedOnDistance 원문을
// che 지도 CityConst로 실행한 결과(2026-09-23, 생성 절차는 report 참고)다.
const refDistances = readJson<Record<string, Record<string, number[]>>>(
'./fixtures/ref-cities-based-on-distance-che.json'
);
const cheMap = readJson<MapDefinition>('../../../resources/map/map_che.json');
const cityList = cheMap.cities.map((city) => ({ id: city.id, path: city.connections }));
void test('matches Ref JSCitiesBasedOnDistance order for every che city up to 3 distance', () => {
assert.equal(Object.keys(refDistances).length, cityList.length);
for (const city of cityList) {
const expected = refDistances[String(city.id)];
assert.ok(expected, `Ref fixture has city ${city.id}`);
const actual = citiesBasedOnDistance(city.id, cityList, 3);
assert.deepEqual(
Object.fromEntries(actual.map((group) => [String(group.distance), group.cityIds])),
expected,
`city ${city.id}`
);
assert.deepEqual(citiesBasedOnDistance(city.id, cityList, 1), [{ distance: 1, cityIds: expected['1'] }]);
}
});
void test('keeps empty distance rows like Ref when the graph ends early', () => {
const tiny = [
{ id: 1, path: [2] },
{ id: 2, path: [1] },
];
assert.deepEqual(citiesBasedOnDistance(1, tiny, 3), [
{ distance: 1, cityIds: [2] },
{ distance: 2, cityIds: [] },
{ distance: 3, cityIds: [] },
]);
assert.deepEqual(citiesBasedOnDistance(99, tiny, 1), [{ distance: 1, cityIds: [] }]);
});
void test('uses the Ref ProcessCity distance for each general city command', () => {
assert.deepEqual(COMMAND_CITY_DISTANCE_RANGE, {
che_이동: 1,
che_출병: 1,
che_강행: 3,
che_첩보: 3,
che_화계: 3,
che_탈취: 3,
che_파괴: 3,
che_선동: 3,
});
for (const nationCommand of ['che_천도', 'che_수몰', 'che_허보', 'che_초토화', 'che_백성동원', 'che_발령']) {
assert.equal(Object.hasOwn(COMMAND_CITY_DISTANCE_RANGE, nationCommand), false);
}
});