You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
문서 목적: 현재 dungeon_crawler 코드베이스에 실제로 구현된 기능만을 기술한다.
DS&A 팀 프로젝트 평가(PPT·라이브 데모·면접)에서 Run it · Defend it · Compare it를 방어하기 위한 발표용 명세이다.
기존 Spec.md는 설계 초안·To-Be가 혼재되어 있으므로, 본 문서를 발표·제출 시 기준 문서로 사용한다.
1. 프로젝트 개요 및 실행 환경
항목
내용
장르
턴 기반 TUI 로그라이크 (룸 템플릿 기반 던전 크롤러)
목적
DS&A 과제 — 6 Core Features 구현 및 알고리즘·자료구조 정당화
언어
Python 3.9+ (타입 힌팅 typing 사용)
UI
rich 라이브러리 — 좌측 Map / 우측 Status + Log 분할 레이아웃
실행
cd dungeon_crawler && python3 -m dungeon_crawler.main
의존성
rich>=13.7.1 (표준 라이브러리 + rich만 사용)
입력 방식
input() 기반 라인 입력 (\n명령 입력 > 프롬프트 후 키 입력)
테스트
python3 -m unittest discover -s tests — 99 tests, 24 files, 전부 통과
1.1. 평가 3원칙 (Team Project Evaluation Guidance)
원칙
본 프로젝트 대응
Run it
메인 메뉴 → 게임 시작 → 3층 탐험 → 클리어/패배/포기 → 점수·리더보드 저장까지 한 세션 완료
Defend it
§2 각 기능마다 DS/알고리즘, 선택 이유, 코드 위치, 복잡도 명시
Compare it
§2·§7 각 기능마다 대안 알고리즘과 트레이드오프 기술
2. 6대 핵심 기능 및 DS&A 설계 (발표 핵심)
각 절은 평가 PPT 5단계 답변 템플릿에 대응한다:
① DS/알고리즘 명시 → ② 선택 이유 → ③ 코드 위치 → ④ 대안 비교 → ⑤ 복잡도·한계
2.1. Dungeon Map (2D Grid & Graph)
구현 요약
월드 그리드 53×30 (WORLD_WIDTH, WORLD_HEIGHT).
3개 층, 층당 12개 방 (시작 1 + 계단 1 + normal 10).
templates/rooms/{start,stair,normal}/*.txt ASCII 템플릿을 월드 좌표에 스탬핑.
방 간 Spanning Tree + 추가 순환 간선(extra_cycles=2)으로 그래프 구성.
통로는 방 외곽 타일을 연결점으로 잡고, **A***로 경로를 찾은 뒤 protected 영역(타 방 벽·내부)을 뚫지 않고 캐빙.
사용 DS / 알고리즘
2D Grid (set 기반 floor_tiles, _blocked)
Graph (room_nodes, edges)
Prim 유사 Spanning Tree + 랜덤 extra edge
A* (통로 경로)
선택 이유
Grid는 타일 단위 이동·충돌·렌더에 직접 대응.
Spanning Tree는 모든 방을 최소 연결로 보장하고, extra cycle로 탐험 루트 다양화.
Undo — 직전 턴(EndTurnAction 마커까지)의 모든 액션 역실행. 로그: [System] 턴 N의 행동을 되돌렸습니다.
r
Redo — Undo로 되돌린 턴 재적용
(빈 입력)
무시
알 수 없는 키
로그: 알 수 없는 입력입니다.
Undo/Redo 후 플레이어가 새 행동을 하면 Redo 스택이 초기화된다 (UndoManager 규칙).
공격 모드 중c/v를 다시 누르면 모드가 덮어씌워진다. esc로 모드만 취소하는 전용 키는 없다.
3.2.5. 이동·공격 방향
키
방향
좌표 변화
w
위
dy = -1
s
아래
dy = +1
a
왼쪽
dx = -1
d
오른쪽
dx = +1
일반 이동: 공격 모드가 꺼져 있을 때 WASD는 이동. 적이 있는 칸으로 가면 이동 대신 근접 공격.
공격 모드:c 또는 v 입력 이후 WASD는 이동이 아니라 해당 방향 공격/발사.
공격 모드에서 방향을 정하면 pending_attack_mode가 해제된다 (한 번의 공격 시도 후 모드 종료).
3.2.6. 인벤토리·화살
항목
설명
슬롯
10칸 (19 = 슬롯 19, 0 = 슬롯 10)
표시
i로 토글. key:아이콘 또는 key:- (빈 칸)
아이템 종류
하트 6종 (❤️🧡💛💚💙💜), 회복량 3~30
HP 가득
회복 아이템 사용 거부, 로그: 체력이 가득 차 아이템을 사용할 수 없습니다.
화살 🏹
인벤토리 슬롯 아님. Status Arrows: N. 시작 3개. v+방향 발사 시 1 소모 (명중/빗나감 무관)
3.2.7. 종료·포기
입력
결과
리더보드
q / esc (인게임)
메인 메뉴 복귀 (retreat)
현재까지 점수 저장
HP ≤ 0
패배 (defeat)
저장
3층 계단 클리어
승리 (victory)
저장
3.2.8. 한 턴의 흐름 (조작 관점)
[화면 렌더] → 명령 입력 > (한 키 + Enter)
→ (턴 소모 행동이면) 플레이어 액션 실행
→ run_enemy_turns() # 현재 층 적 전원
→ finalize_turn() # turn_id++, EndTurnAction
→ (승리/패배 검사)
[다시 화면 렌더]
턴을 소모하지 않은 입력(모드 전환, Undo, 인벤토리 토글 등)은 적 턴 없이 바로 다음 입력을 받는다.
3.2.9. 빠른 참조표
입력
동작
턴 소모
w / a / s / d
이동 (또는 공격 모드 시 방향 공격)
성공 시 ○
c
근접 모드 진입
×
v
원거리 모드 진입
×
1 ~ 9, 0
슬롯 아이템 사용
성공 시 ○
i
인벤토리 표시 토글
×
u / r
Undo / Redo
×
q / esc
메인 메뉴 포기
× (세션 종료)
(빈 입력)
무시
×
3.3. 전투·원거리
근접: 인접 타일 적에게 CombatAction (이동으로 충돌 시에도 전투).
원거리: 직선 궤적 추적. 벽·맵 밖·바닥 아이템에서 정지. 적 명중 시 CombatAction.
화살: 발사 시 1 소모 (명중/빗나감 무관). Entity.arrows에서 차감.
3.4. 층·계단·승리 조건
3개 층 독립 생성 (FloorManager).
계단 타일(2) 위로 이동 시 자동 하강 → 다음 층 start_spawn.
3층 계단 진입 시 dungeon_cleared = True → 클리어 (victory).
패배: HP ≤ 0. 포기: q / esc.
3.5. 세션 시드
derive_session_seed() = time.time_ns() % 2**31 (게임 시작 시각).
AI+X Studio 컴퓨터에서 python3 -m dungeon_crawler.main 실행 확인
시작 → 플레이 → 클리어/패배/포기 → 리더보드 저장까지 크래시 없음
6대 기능 코드 존재 (§2 참조)
각 기능 DS/알고리즘·대안·복잡도 설명 가능
PPT 내용이 본 문서(Spec_Implemented.md) 와 일치
각 기능 파일명·함수명 암기 (§2 코드 위치 표)
§7.3 예상 질문 리허설
7.2. 기능별 5단계 답변 스크립트 (Slide 10)
Dungeon Map
"We use a 2D Grid and a Graph (spanning tree + A* corridors). The grid maps directly to walkability and rendering; the graph guarantees all rooms are connected. Code is in generation/floor_generator.py and corridor_carver.py. BFS could connect rooms too, but we use greedy spanning tree for simplicity; straight L-corridors cut through rooms, so we use A* with protected cells. Grid lookup is O(1); spanning tree is O(R²) for R≤12 rooms."
Undo System
"We use a two-stack LIFO structure with the Command Pattern. Undo is last-in-first-out, matching Stack access. UndoManager in engine/undo_manager.py pushes MoveAction, CombatAction, etc., and pops until EndTurnAction. A Queue would replay in the wrong order. Push/pop are O(1); memory grows with actions per session."
Turn Management
"We use a batch resolve loop: player acts, then TurnResolver.collect_actions() validates enemy proposals, then GameManager executes them. TurnManager only tracks turn_id and per-turn RNG seed. A FIFO per-entity queue (in our old Spec) would rotate all entities fairly, but player-then-enemies phases fit our TUI better. Enemy fallback tries up to 8 validated proposals per turn."
Item Inventory
"We use a List for 10 UI slots and a defaultdict Hash Map for name counts in models/inventory.py. Arrows are a separate Entity.arrows int, not inventory slots. A Tree would be overkill for 10 slots; Dict-only loses slot order for keys 1–0."
Enemy AI
"We use A* in utils/pathfinding.py with Manhattan heuristic. Enemies within radius 6 chase; otherwise wander. Blockers include items and other enemies; we retry with expanded blockers. BFS gives the same shortest path on unweighted grids; DFS doesn't guarantee shortest. A* is O(E log V) on the grid."
Leaderboard
"We use Insertion Sort on a small array (capacity 10) in utils/leaderboard.py. Only top-10 matters; n is tiny so O(n²) is fine. A Heap would be O(n log k) for larger n, but unnecessary here. Scores persist to leaderboard.json."