// Semantic Hunter Game Frontend /** * UI类 - 负责DOM操作和UI渲染 */ class SemanticHunterUI { constructor() { // DOM元素 this.guessInput = document.getElementById('guess-input'); this.guessBtn = document.getElementById('guess-btn'); this.messageArea = document.getElementById('message-area'); this.guessesList = document.getElementById('guesses-list'); this.newGameBtn = document.getElementById('new-game-btn'); this.itemsPerPage = 7; } // 清空输入框并聚焦 clearAndFocusInput() { this.guessInput.value = ''; this.guessInput.focus(); } // 获取输入值 getInputValue() { return this.guessInput.value.trim(); } // 显示消息 showMessage(msg) { this.messageArea.innerHTML = `
`; } // 显示错误消息 showError(msg) { this.messageArea.innerHTML = ` `; } // 显示成功消息 showSuccess(msg) { this.messageArea.innerHTML = ` `; } // 重置猜测列表 resetGuessList() { this.guessesList.innerHTML = ''; this.messageArea.innerHTML = ''; } // 获取相似度样式类 getSimilarityClass(similarity) { if (similarity === 100) { return 'similarity-perfect'; } else if (similarity >= 90) { return 'similarity-super-high'; } else if (similarity >= 80) { return 'similarity-very-high'; } else if (similarity >= 70) { return 'similarity-high'; } else if (similarity >= 50) { return 'similarity-medium'; } else { return 'similarity-low'; } } // 渲染猜测列表,包括最新猜测和历史猜测 renderGuessList(guesses, latestGuess, currentPage) { this.guessesList.innerHTML = ''; // 渲染最新猜测(如果有) if (latestGuess) { this.renderLatestGuess(latestGuess, guesses); } // 渲染历史猜测列表 this.renderHistoryGuesses(guesses, latestGuess, currentPage); return guesses; } // 渲染最新猜测(置顶显示) renderLatestGuess(latestGuess, guesses) { // 寻找最新猜测的详细信息 const latestGuessData = guesses.find(g => g.word === latestGuess.word); if (!latestGuessData) return; // 创建最新猜测的容器 const latestGuessContainer = document.createElement('div'); latestGuessContainer.className = 'latest-guess-container'; // 添加最新猜测并使用不同样式 const latestGuessElement = document.createElement('div'); latestGuessElement.className = 'latest-guess'; // 如果100%匹配,添加perfect-match类 if (latestGuessData.similarity === 100) { latestGuessElement.classList.add('perfect-match'); } // 确定相似度颜色类 const similarityClass = this.getSimilarityClass(latestGuessData.similarity); latestGuessElement.innerHTML = ` ${latestGuessData.word} ${latestGuessData.similarity}% `; latestGuessContainer.appendChild(latestGuessElement); // 添加分隔线 const separator = document.createElement('div'); separator.className = 'guess-separator'; latestGuessContainer.appendChild(separator); this.guessesList.appendChild(latestGuessContainer); } // 渲染历史猜测列表 renderHistoryGuesses(guesses, latestGuess, currentPage) { // 创建历史猜测的容器 const historyContainer = document.createElement('div'); historyContainer.className = 'history-guesses-container'; // 获取当前页的项目 const startIndex = (currentPage - 1) * this.itemsPerPage; const endIndex = Math.min(startIndex + this.itemsPerPage, guesses.length); const currentPageItems = guesses.slice(startIndex, endIndex); // 添加当前页的猜测 currentPageItems.forEach(guess => { // 如果有最新猜测且与当前历史猜测相同,则跳过(避免重复显示) if (latestGuess && guess.word === latestGuess.word) { return; } const guessItem = document.createElement('div'); guessItem.className = 'guess-item'; // 如果100%匹配,添加perfect-match类 if (guess.similarity === 100) { guessItem.classList.add('perfect-match'); } // 确定相似度颜色类 const similarityClass = this.getSimilarityClass(guess.similarity); guessItem.innerHTML = ` ${guess.word} ${guess.similarity}% `; historyContainer.appendChild(guessItem); }); this.guessesList.appendChild(historyContainer); } // 添加分页控件 addPagination(allGuesses, currentPage, onPageChange) { const totalPages = Math.ceil(allGuesses.length / this.itemsPerPage); if (totalPages <= 1) return; // 如果只有一页,不显示分页控件 // 创建分页容器 const paginationContainer = document.createElement('div'); paginationContainer.className = 'pagination-container'; // 上一页按钮 const prevBtn = document.createElement('button'); prevBtn.className = 'pagination-btn prev-btn'; prevBtn.innerHTML = ``; prevBtn.disabled = currentPage === 1; prevBtn.addEventListener('click', () => { if (currentPage > 1) { onPageChange(currentPage - 1); } }); // 页面指示器 const pageIndicator = document.createElement('div'); pageIndicator.className = 'page-indicator'; pageIndicator.textContent = `${currentPage} / ${totalPages}`; // 下一页按钮 const nextBtn = document.createElement('button'); nextBtn.className = 'pagination-btn next-btn'; nextBtn.innerHTML = ``; nextBtn.disabled = currentPage === totalPages; nextBtn.addEventListener('click', () => { if (currentPage < totalPages) { onPageChange(currentPage + 1); } }); // 将按钮添加到容器 paginationContainer.appendChild(prevBtn); paginationContainer.appendChild(pageIndicator); paginationContainer.appendChild(nextBtn); // 添加到DOM this.guessesList.appendChild(paginationContainer); } } /** * API类 - 负责与后端通信 */ class SemanticHunterAPI { // 获取当前游戏状态 async getGameStatus() { try { const response = await fetch('/game-status', { method: 'GET', headers: { 'Content-Type': 'application/json' } }); return await response.json(); } catch (error) { console.error('获取游戏状态时出错:', error); throw new Error('无法连接到服务器'); } } // 初始化新游戏 async initGame() { try { const response = await fetch('/new-game', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); return await response.json(); } catch (error) { console.error('初始化游戏时出错:', error); throw new Error('无法连接到服务器'); } } // 提交猜测 async submitGuess(guess) { try { const response = await fetch('/guess', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ guess }) }); return await response.json(); } catch (error) { console.error('提交猜测时出错:', error); throw new Error('无法连接到服务器'); } } } /** * 游戏控制器 - 处理游戏逻辑 */ class SemanticHunterGame { constructor() { this.ui = new SemanticHunterUI(); this.api = new SemanticHunterAPI(); // 游戏状态 this.gameActive = true; // 默认假设游戏是活跃的 this.latestGuess = null; // 只在前端存储最新猜测 this.allGuesses = []; // 所有猜测历史 this.currentPage = 1; // 当前分页 // 初始设置新游戏按钮为禁用状态 this.ui.newGameBtn.disabled = true; // 初始化事件监听器 this.initEventListeners(); // 加载游戏状态 this.loadGameStatus(); } // 初始化事件监听器 initEventListeners() { this.ui.guessBtn.addEventListener('click', () => this.submitGuess()); this.ui.guessInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') this.submitGuess(); }); this.ui.newGameBtn.addEventListener('click', () => this.initGame()); } // 加载游戏状态 - 从后端获取当前状态 async loadGameStatus() { try { const data = await this.api.getGameStatus(); if (data.status === 'success') { // 更新游戏状态 this.allGuesses = data.guesses; this.gameActive = !data.has_correct_guess; // 如果有猜测历史,渲染它们 if (this.allGuesses.length > 0) { // 不指定最新猜测,所有猜测都在历史列表中显示 this.updateGuessList(this.allGuesses, null); // 如果已经猜对了 if (!this.gameActive) { const correctGuess = this.allGuesses.find(g => g.is_correct); if (correctGuess) { this.ui.showSuccess(`有人已经猜对了! 秘密词语是: ${correctGuess.word}`); } } else { this.ui.showMessage('游戏进行中! 尝试猜测秘密词语!'); } } else { this.ui.showMessage('游戏开始! 尝试猜测秘密词语!'); } // 更新新游戏按钮状态 this.updateNewGameButton(); // 清空输入框并聚焦 this.ui.clearAndFocusInput(); } else { this.ui.showError('获取游戏状态失败'); } } catch (error) { this.ui.showError(error.message); } } // 初始化游戏 - 创建新游戏 async initGame() { try { const data = await this.api.initGame(); if (data.status === 'success') { this.gameActive = true; this.ui.resetGuessList(); this.ui.clearAndFocusInput(); this.allGuesses = []; this.latestGuess = null; this.currentPage = 1; this.ui.showMessage('新游戏开始! 尝试猜测秘密词语!'); // 更新新游戏按钮状态 this.updateNewGameButton(); } else { this.ui.showError(data.message || '初始化游戏时出错'); } } catch (error) { this.ui.showError(error.message); } } // 提交猜测 async submitGuess() { const guessWord = this.ui.getInputValue(); if (!guessWord) return; if (!this.gameActive) { this.ui.showError('游戏已结束,请点击新游戏'); return; } try { const data = await this.api.submitGuess(guessWord); if (data.status === 'success') { // 更新猜测历史 this.allGuesses = data.guesses; // 在前端存储最新的猜测 this.latestGuess = { word: guessWord, similarity: data.similarity, is_correct: data.is_correct }; // 渲染猜测列表,将最新猜测置顶 this.updateGuessList(this.allGuesses, this.latestGuess); // 根据猜测结果更新游戏状态和显示消息 if (data.is_correct) { this.gameActive = false; this.ui.showSuccess(`恭喜你猜对了! 秘密词语是: ${guessWord}`); } else { this.ui.showMessage(`相似度: ${data.similarity}%`); } // 更新新游戏按钮状态 this.updateNewGameButton(); // 清空输入框并聚焦 this.ui.clearAndFocusInput(); } else { this.ui.showError(data.message || '提交猜测时出错'); } } catch (error) { this.ui.showError(error.message); } } // 更新猜测列表 - 同时处理最新猜测和历史猜测 updateGuessList(guesses, latestGuess) { // 渲染猜测列表 this.ui.renderGuessList(guesses, latestGuess, this.currentPage); // 如果有多页,添加分页控件 if (guesses.length > this.ui.itemsPerPage) { this.ui.addPagination(guesses, this.currentPage, (newPage) => { this.currentPage = newPage; this.updateGuessList(guesses, latestGuess); }); } } // 更新新游戏按钮状态 updateNewGameButton() { // 检查是否有正确的猜测 const hasCorrectGuess = this.allGuesses.some(guess => guess.is_correct); // 只有在游戏已结束(有正确猜测)时,新游戏按钮才可用 this.ui.newGameBtn.disabled = !hasCorrectGuess; } } // 当DOM内容加载完成时初始化游戏 document.addEventListener('DOMContentLoaded', () => { new SemanticHunterGame(); });