# 웹 카탄 게임 만들기 - Part 10: 테스트 및 최종 완성 ## 이번 파트에서 구현할 내용 - 종합 테스트 체크리스트 - 게임 재시작 기능 - 피드백 시스템 구현 - 최종 통합 및 main.js 완성 - 배포 준비 --- ## Step 1: 테스트 체크리스트 게임 출시 전 확인해야 할 항목들입니다. ### 기본 기능 테스트 ```markdown ### 게임 설정 - [ ] AI 수 선택 (1~3명)이 정상 작동 - [ ] 난이도 선택 (쉬움/보통/어려움)이 정상 작동 - [ ] 게임 시작 버튼 클릭 시 게임 화면으로 전환 - [ ] 튜토리얼 모달 표시 및 닫기 ### 초기 배치 단계 - [ ] 정착지 배치 가능 위치 하이라이트 - [ ] 도로 배치 가능 위치 하이라이트 - [ ] 1라운드 순방향 진행 - [ ] 2라운드 역방향 진행 - [ ] 2라운드 시 인접 타일 자원 획득 - [ ] AI 초기 배치 자동 진행 ### 주사위 & 자원 - [ ] 주사위 굴리기 애니메이션 - [ ] 자원 분배 정확성 - [ ] 도시는 2배 자원 생산 - [ ] 도둑 타일은 자원 생산 안 함 - [ ] 숫자 7: 8장 이상 보유 시 절반 버림 - [ ] 숫자 7: 도둑 이동 UI ### 건설 - [ ] 도로 건설: 비용 확인 및 차감 - [ ] 도로 건설: 연결 규칙 - [ ] 정착지 건설: 비용 확인 및 차감 - [ ] 정착지 건설: 거리 규칙 - [ ] 정착지 건설: 도로 연결 필수 - [ ] 도시 업그레이드: 비용 확인 및 차감 ### 거래 - [ ] 은행 거래: 4:1 비율 - [ ] 항구 거래: 3:1, 2:1 비율 - [ ] AI 거래 제안 및 응답 ### 개발 카드 - [ ] 구매 비용 차감 - [ ] 구매 턴에 사용 불가 - [ ] 기사: 도둑 이동 - [ ] 도로 건설: 무료 도로 2개 - [ ] 풍년: 자원 2개 선택 - [ ] 독점: 특정 자원 모두 가져오기 - [ ] 승점: 점수 반영 ### 특별 점수 - [ ] 최장 도로 계산 정확성 - [ ] 최장 도로 5개 이상 시 2점 - [ ] 최대 기사단 3장 이상 시 2점 - [ ] 소유권 이전 처리 ### 게임 종료 - [ ] 10점 달성 시 게임 종료 - [ ] 승자 표시 - [ ] 점수 상세 내역 표시 - [ ] 재시작 버튼 작동 - [ ] 메인으로 버튼 작동 ### AI - [ ] AI 턴 자동 진행 - [ ] AI 건설 로직 - [ ] AI 난이도별 차이 - [ ] AI 턴 딜레이 (자연스러움) ``` --- ## Step 2: 게임 재시작 기능 ```javascript // Game 클래스에 추가 class Game { // 게임 재시작 restart() { // 상태 초기화 this.board = new Board(); this.board.initialize(); this.players.forEach((player, index) => { player.resources = { [RESOURCES.GRAIN]: 0, [RESOURCES.BRICK]: 0, [RESOURCES.LUMBER]: 0, [RESOURCES.WOOL]: 0, [RESOURCES.ORE]: 0 }; player.devCards = []; player.newDevCards = []; player.usedKnights = 0; player.settlements = 0; player.cities = 0; player.roads = 0; player.hasLongestRoad = false; player.hasLargestArmy = false; }); this.currentPlayerIndex = 0; this.turnNumber = 0; this.winner = null; // 개발 카드 덱 리셋 this.devCardManager = new DevCardManager(this); // 셋업 단계로 this.phase = GAME_PHASES.SETUP; this.setupRound = 1; this.setupStep = 'settlement'; // 게임 로그 초기화 const logContent = document.getElementById('log-content'); if (logContent) logContent.innerHTML = ''; logMessage('🔄 게임이 재시작되었습니다!'); logMessage('📍 초기 배치 단계: 정착지와 도로를 배치하세요.'); // UI 업데이트 this.uiManager.boardRenderer.render(); this.uiManager.updateUI(); // 셋업 진행 this.processSetupPhase(); } // 빠른 재시작 (설정 유지) quickRestart() { this.restart(); } // 새 게임 (설정 화면으로) newGame() { document.getElementById('game-screen').classList.remove('active'); document.getElementById('setup-screen').classList.add('active'); } } ``` --- ## Step 3: 피드백 시스템 ```javascript // js/ui/FeedbackSystem.js class FeedbackSystem { constructor() { this.bindEvents(); } bindEvents() { // 피드백 버튼 document.getElementById('feedback-btn').addEventListener('click', () => { this.openFeedbackModal(); }); // 모달 닫기 document.querySelector('#feedback-modal .close-btn').addEventListener('click', () => { this.closeFeedbackModal(); }); // 피드백 제출 document.getElementById('submit-feedback').addEventListener('click', () => { this.submitFeedback(); }); } openFeedbackModal() { document.getElementById('feedback-modal').classList.add('active'); document.getElementById('feedback-text').focus(); } closeFeedbackModal() { document.getElementById('feedback-modal').classList.remove('active'); document.getElementById('feedback-text').value = ''; } submitFeedback() { const text = document.getElementById('feedback-text').value.trim(); if (!text) { alert('피드백 내용을 입력해주세요.'); return; } // 피드백 데이터 수집 const feedbackData = { message: text, timestamp: new Date().toISOString(), gameState: this.getGameState(), userAgent: navigator.userAgent }; // 로컬 스토리지에 저장 (실제로는 서버로 전송) this.saveFeedback(feedbackData); // 확인 메시지 alert('피드백이 전송되었습니다. 감사합니다!'); this.closeFeedbackModal(); } getGameState() { // 현재 게임 상태 요약 if (typeof game === 'undefined') return null; return { phase: game.phase, turnNumber: game.turnNumber, playerCount: game.players.length, aiDifficulty: game.players[1]?.aiDifficulty }; } saveFeedback(data) { const feedbacks = JSON.parse(localStorage.getItem('catanFeedbacks') || '[]'); feedbacks.push(data); localStorage.setItem('catanFeedbacks', JSON.stringify(feedbacks)); console.log('Feedback saved:', data); } } ``` --- ## Step 4: 게임 기록 저장 ```javascript // js/game/GameHistory.js class GameHistory { constructor() { this.history = []; this.maxHistory = 10; } // 게임 결과 저장 saveGameResult(game) { const result = { id: Date.now(), date: new Date().toISOString(), winner: { name: game.winner.name, isAI: game.winner.isAI, score: game.scoreManager.getActualScore(game.winner.id) }, players: game.players.map(p => ({ name: p.name, isAI: p.isAI, score: game.scoreManager.getActualScore(p.id) })), turnCount: game.turnNumber, aiDifficulty: game.players.find(p => p.isAI)?.aiDifficulty, duration: this.calculateDuration(game) }; this.history.unshift(result); // 최대 개수 제한 if (this.history.length > this.maxHistory) { this.history.pop(); } this.saveToStorage(); return result; } calculateDuration(game) { // 게임 시간 계산 (실제 구현 시 시작 시간 기록 필요) return game.turnNumber * 30; // 대략적인 초 단위 } // 로컬 스토리지에 저장 saveToStorage() { localStorage.setItem('catanHistory', JSON.stringify(this.history)); } // 로컬 스토리지에서 로드 loadFromStorage() { const saved = localStorage.getItem('catanHistory'); if (saved) { this.history = JSON.parse(saved); } } // 기록 가져오기 getHistory() { return this.history; } // 통계 계산 getStats() { if (this.history.length === 0) return null; const wins = this.history.filter(g => !g.winner.isAI).length; const totalGames = this.history.length; const avgTurns = this.history.reduce((sum, g) => sum + g.turnCount, 0) / totalGames; return { totalGames, wins, losses: totalGames - wins, winRate: ((wins / totalGames) * 100).toFixed(1), avgTurns: avgTurns.toFixed(1) }; } } ``` --- ## Step 5: main.js 최종 통합 ```javascript // js/main.js // 전역 변수 let game = null; let setupScreen = null; let feedbackSystem = null; let gameHistory = null; // DOM 로드 완료 시 초기화 document.addEventListener('DOMContentLoaded', () => { console.log('🏝️ 카탄 웹 게임 초기화...'); // 시스템 초기화 setupScreen = new SetupScreen(); feedbackSystem = new FeedbackSystem(); gameHistory = new GameHistory(); gameHistory.loadFromStorage(); // 초기 화면 설정 document.getElementById('setup-screen').classList.add('active'); // 키보드 단축키 initKeyboardShortcuts(); console.log('✅ 초기화 완료!'); }); // 키보드 단축키 function initKeyboardShortcuts() { document.addEventListener('keydown', (e) => { // ESC: 선택 취소 또는 모달 닫기 if (e.key === 'Escape') { closeAllModals(); if (game && game.uiManager) { game.uiManager.boardRenderer.clearSelectionMode(); } } // 게임 중 단축키 if (game && game.phase !== GAME_PHASES.SETUP && !game.getCurrentPlayer().isAI) { switch (e.key) { case 'r': // R: 도로 건설 if (!e.ctrlKey && !e.metaKey) { document.getElementById('btn-build-road').click(); } break; case 's': // S: 정착지 건설 if (!e.ctrlKey && !e.metaKey) { document.getElementById('btn-build-settlement').click(); } break; case 'c': // C: 도시 건설 if (!e.ctrlKey && !e.metaKey) { document.getElementById('btn-build-city').click(); } break; case 'd': // D: 개발 카드 구매 document.getElementById('btn-buy-card').click(); break; case 't': // T: 거래 document.getElementById('btn-trade').click(); break; case 'Enter': // Enter: 턴 종료 if (game.phase === GAME_PHASES.MAIN) { document.getElementById('btn-end-turn').click(); } else if (game.phase === GAME_PHASES.ROLL_DICE) { document.getElementById('roll-dice').click(); } break; } } }); } // 모든 모달 닫기 function closeAllModals() { document.querySelectorAll('.modal.active').forEach(modal => { modal.classList.remove('active'); }); } // 게임 인스턴스 설정 (SetupScreen에서 호출) function setGameInstance(gameInstance) { game = gameInstance; } // 에러 핸들링 window.onerror = function(msg, url, lineNo, columnNo, error) { console.error('Error: ', msg, '\nURL: ', url, '\nLine: ', lineNo); // 사용자에게 알림 if (game && game.uiManager) { game.uiManager.showToast('오류가 발생했습니다. 게임을 재시작해주세요.', 'error'); } return false; }; // 페이지 떠날 때 경고 window.onbeforeunload = function(e) { if (game && game.phase !== GAME_PHASES.SETUP && game.phase !== GAME_PHASES.GAME_OVER) { e.preventDefault(); e.returnValue = ''; return '게임이 진행 중입니다. 정말 나가시겠습니까?'; } }; ``` --- ## Step 6: 최종 파일 목록 ``` catan-game/ ├── index.html ├── css/ │ ├── style.css # 전역 스타일, 설정 화면 │ ├── board.css # 게임 보드 스타일 │ ├── ui.css # UI 컴포넌트, 모달 │ └── animations.css # 애니메이션 (선택적) ├── js/ │ ├── main.js # 앱 진입점 │ ├── utils/ │ │ ├── constants.js # 게임 상수 │ │ └── helpers.js # 유틸리티 함수 │ ├── game/ │ │ ├── Game.js # 게임 로직 │ │ ├── Board.js # 보드 관리 │ │ ├── Tile.js # 타일 클래스 │ │ ├── Player.js # 플레이어 클래스 │ │ ├── Building.js # 건물 관리 │ │ ├── DevCard.js # 개발 카드 │ │ ├── TradeManager.js # 거래 관리 │ │ ├── DevCardManager.js # 개발카드 관리 │ │ ├── ScoreManager.js # 점수 관리 │ │ └── GameHistory.js # 게임 기록 │ ├── ai/ │ │ ├── AI.js # AI 기본 클래스 │ │ ├── EasyAI.js # 쉬움 난이도 │ │ ├── MediumAI.js # 보통 난이도 │ │ └── HardAI.js # 어려움 난이도 │ └── ui/ │ ├── UIManager.js # UI 총괄 │ ├── BoardRenderer.js # 보드 렌더링 │ ├── SetupScreen.js # 설정 화면 │ ├── TradeUI.js # 거래 UI │ ├── DevCardUI.js # 개발카드 UI │ └── FeedbackSystem.js # 피드백 시스템 └── README.md # 프로젝트 설명 ``` --- ## Step 7: 배포 체크리스트 ```markdown ### 배포 전 확인사항 - [ ] 모든 JavaScript 파일 로드 순서 확인 - [ ] 콘솔 에러 없음 확인 - [ ] 브라우저 호환성 테스트 (Chrome, Firefox, Safari, Edge) - [ ] 성능 테스트 (긴 게임 플레이 시 메모리 누수 확인) - [ ] 반응형은 제외하되 최소 해상도 확인 (1280x720) ### 선택적 개선사항 - [ ] JavaScript 압축 (minify) - [ ] CSS 압축 - [ ] 이미지 최적화 (사용 시) - [ ] 로딩 화면 추가 - [ ] PWA 지원 (오프라인 플레이) - [ ] 다국어 지원 ``` --- ## 시리즈 완료! 10개 파트에 걸쳐 순수 HTML, CSS, JavaScript만으로 웹 기반 카탄 게임을 완성했습니다. ### 구현된 기능 요약 ✅ **게임 설정**: AI 수 및 난이도 선택 ✅ **헥사곤 보드**: SVG 기반 동적 렌더링 ✅ **자원 시스템**: 5가지 자원, 주사위 기반 분배 ✅ **건설**: 도로, 정착지, 도시 ✅ **거래**: 은행 거래, 항구, 플레이어 간 거래 ✅ **개발 카드**: 5종류 카드 구현 ✅ **특별 점수**: 최장 도로, 최대 기사단 ✅ **AI**: 3단계 난이도 ✅ **UI/UX**: 직관적 인터페이스, 튜토리얼 ### 향후 개선 가능 사항 - 멀티플레이어 (WebSocket) - 보드 커스터마이징 - 확장판 규칙 - 모바일 지원 - 사운드 효과 --- ## 전체 시리즈 목차 1. [Part 1 - 프로젝트 소개](make-web-katan-game-v1.md) 2. [Part 2 - 헥사곤 게임 보드](make-web-katan-game-v2.md) 3. [Part 3 - 자원 시스템 및 주사위](make-web-katan-game-v3.md) 4. [Part 4 - 건설 시스템](make-web-katan-game-v4.md) 5. [Part 5 - 거래 시스템](make-web-katan-game-v5.md) 6. [Part 6 - 개발 카드 시스템](make-web-katan-game-v6.md) 7. [Part 7 - 특별 점수 시스템](make-web-katan-game-v7.md) 8. [Part 8 - AI 구현](make-web-katan-game-v8.md) 9. [Part 9 - 게임 설정 및 UI 완성](make-web-katan-game-v9.md) 10. [Part 10 - 테스트 및 최종 완성](make-web-katan-game-v10.md) --- *읽어주셔서 감사합니다! 🎲*