feat(map): 맵 5막화·노드 depth 7·rest/shop/elite 연속 금지 (P14-1)

- ACT_COUNT/RUN_LENGTH 3→5, ACT_MAPS map01~map05 (반복 런 기반 확장)
- MAP_ROWS 7→6 (걷는 행 6 + 보스 = depth 최대 7), 막 배율 0.6→0.45 완화
- 노드 타입 인접 금지를 elite 단독 → rest/shop/elite 3종으로 일반화
  (Lua GenerateMap + rogue-map.mjs JS 미러 동시 수정, 테스트 9/9 통과)
- 맵 파일 생성기 카운트 11→5, map06~map11 삭제, SectorConfig 정리(stale 제거)
- 산출물 재생성(ui/codeblock/map01~05). 검증 헬퍼 tools/verify/count.mjs 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 00:13:16 +09:00
parent f67471435e
commit 9e16465218
24 changed files with 2886 additions and 52399 deletions

View File

@@ -61,7 +61,7 @@ test('타입 규칙: 1~2행 combat만, elite·treasure는 4행부터, shop·rest
}
});
test('boss: row 8 단일 노드, 7행 노드는 전부 boss로 연결', () => {
test('boss: row 7 단일 노드, 마지막 걷는 행 노드는 전부 boss로 연결', () => {
for (let s = 1; s <= 30; s++) {
const { nodes } = gen(s);
const bosses = Object.entries(nodes).filter(([, n]) => n.type === 'boss');
@@ -90,19 +90,21 @@ test('간선 제약: row+1로만, 열 차이 1 이하 (boss 간선 제외)', ()
}
});
test('elite 연속 금지: elite 부모를 가진 노드는 elite 아님', () => {
test('연속 금지: rest/shop/elite 부모와 같은 타입을 자식으로 두지 않음', () => {
const NO_REPEAT = new Set(['rest', 'shop', 'elite']);
for (let s = 1; s <= 100; s++) {
const { nodes } = gen(s);
for (const [id, n] of Object.entries(nodes)) {
if (n.type !== 'elite') continue;
if (!NO_REPEAT.has(n.type)) continue;
for (const nid of n.next) {
assert.notEqual(nodes[nid].type, 'elite', `seed ${s}: ${id}(elite) → ${nid}(elite)`);
if (nid === 'boss') continue;
assert.notEqual(nodes[nid].type, n.type, `seed ${s}: ${id}(${n.type}) → ${nid}(${n.type})`);
}
}
}
});
test('그리드 범위: 행 1..8, 열 1..4 (boss 제외)', () => {
test('그리드 범위: 행 1..6, 열 1..4 (boss 제외)', () => {
const { nodes } = gen(7);
for (const [id, n] of Object.entries(nodes)) {
if (id === 'boss') continue;