猜数字游戏:从数学原理到交互体验的完整设计指南

目录

  • 猜数字游戏:从数学原理到交互体验的完整设计指南
    • 引言
    • 第一章 游戏数学原理
      • 1.1 均匀分布与随机生成
      • 1.2 最优猜测策略
    • 第二章 游戏系统设计
      • 2.1 核心架构
      • 2.2 动态难度系统
    • 第三章 交互设计细节
      • 3.1 输入验证系统
      • 3.2 渐进式提示机制
    • 第四章 进阶功能设计
      • 4.1 智能辅导系统
      • 4.2 数据驱动平衡
    • 第五章 性能优化
      • 5.1 内存管理策略
      • 5.2 实时反馈优化
    • 第六章 测试与调试
      • 6.1 自动化测试矩阵
      • 6.2 蒙特卡洛测试
    • 结语
    • 附录:部分代码

猜数字游戏:从数学原理到交互体验的完整设计指南

引言

猜数字游戏作为编程教学中的"Hello World"级项目,其看似简单的表象下蕴含着精妙的数学原理和交互设计哲学。本文将深入解析一个专业级猜数字游戏的设计过程,揭示其背后的概率论基础、算法优化策略以及用户体验设计原则。


第一章 游戏数学原理

1.1 均匀分布与随机生成

游戏核心依赖的随机数生成遵循离散均匀分布原理:

P ( X = k ) = 1 N , k ∈ [ 1 , N ] P(X=k) = \frac{1}{N},\quad k \in [1,N] P(X=k)=N1,k∈[1,N]

其中 N N N表示数字范围上限。现代编程语言通常采用梅森旋转算法 (Mersenne Twister)生成伪随机数,其周期长度达 2 19937 − 1 2^{19937}-1 219937−1,通过以下步骤实现理想随机性:

  1. 系统时间播种: s e e d = ⌊ t i m e s t a m p × 1 0 3 ⌋ seed = \lfloor timestamp \times 10^3 \rfloor seed=⌊timestamp×103⌋
  2. 范围映射: t a r g e t = ⌊ r a n d ( ) × ( m a x − m i n ) ⌋ + m i n target = \lfloor rand() \times (max-min) \rfloor + min target=⌊rand()×(max−min)⌋+min

1.2 最优猜测策略

采用二分查找算法时,最大猜测次数满足:

T m a x = ⌈ log ⁡ 2 N ⌉ T_{max} = \lceil \log_2 N \rceil Tmax=⌈log2N⌉

当 N = 100 N=100 N=100时,理论最小次数为7次。实际游戏中玩家平均尝试次数为:

E ( T ) = ∑ k = 1 log ⁡ 2 N 2 k − 1 N k E(T) = \sum_{k=1}^{\log_2 N} \frac{2^{k-1}}{N}k E(T)=k=1∑log2NN2k−1k


第二章 游戏系统设计

2.1 核心架构

进行中 胜利 失败 游戏引擎 随机生成模块 输入处理模块 反馈生成模块 游戏状态机 游戏状态 等待输入 显示结果 展示答案

2.2 动态难度系统

通过实时监测玩家表现调整参数:

指标 调节策略 数学表达式
连续失败次数 缩小数字范围 N n e w = ⌊ 0.8 N ⌋ N_{new} = \lfloor 0.8N \rfloor Nnew=⌊0.8N⌋
平均响应时间 调整倒计时长度 t l i m i t = m a x ( 10 , 30 − T ‾ ) t_{limit} = max(10, 30-\overline{T}) tlimit=max(10,30−T)
历史胜率 动态平衡随机分布 μ = μ ± σ / 2 \mu = \mu \pm \sigma/2 μ=μ±σ/2

第三章 交互设计细节

3.1 输入验证系统

建立多层防护体系:

  1. 类型过滤 :正则表达式^[1-9]\d*$
  2. 范围检查 : i n p u t ∈ [ l a s t L o w , l a s t H i g h ] input \in [lastLow, lastHigh] input∈[lastLow,lastHigh]
  3. 历史检测 : i n p u t ∉ H i s t o r y S e t input \notin HistorySet input∈/HistorySet

3.2 渐进式提示机制

根据尝试次数动态释放提示:

尝试次数 提示类型 触发条件
1-3 范围指示条 每次猜测后更新
4-5 质数高亮 涉及质数时触发
≥6 数字热度图 累计数据超过20条

第四章 进阶功能设计

4.1 智能辅导系统

采用贝叶斯推理实时分析玩家策略:

P ( S t r a t e g y ∣ A c t i o n s ) = P ( A c t i o n s ∣ S t r a t e g y ) P ( S t r a t e g y ) P ( A c t i o n s ) P(Strategy|Actions) = \frac{P(Actions|Strategy)P(Strategy)}{P(Actions)} P(Strategy∣Actions)=P(Actions)P(Actions∣Strategy)P(Strategy)

系统可识别的典型策略模式包括:

  • 随机猜测(熵值>3.5)
  • 线性搜索(猜测差值标准差<2)
  • 二分法(符合 μ = 0.5 N \mu=0.5N μ=0.5N分布)

4.2 数据驱动平衡

收集以下指标进行游戏平衡:

python 复制代码
metrics = {
    'attempt_dist': [],    # 尝试次数分布
    'time_heatmap': [],    # 时段活跃度
    'dropoff_point': [],   # 玩家流失节点
    'pattern_cluster': []  # 策略聚类
}

第五章 性能优化

5.1 内存管理策略

采用环形缓冲区存储游戏记录:

B u f f e r S i z e = ⌈ log ⁡ 2 N ⌉ × 2 BufferSize = \lceil \log_2 N \rceil \times 2 BufferSize=⌈log2N⌉×2

实现O(1)时间复杂度的历史查询操作。

5.2 实时反馈优化

通过插值算法实现流畅动画:

x t = x 0 + ( x t a r g e t − x 0 ) × 1 − ( 1 − t ) 4 x_{t} = x_{0} + (x_{target}-x_{0}) \times \sqrt{1-(1-t)^4} xt=x0+(xtarget−x0)×1−(1−t)4

R G B c u r r e n t = l e r p ( R G B s t a r t , R G B e n d , t T ) RGB_{current} = lerp(RGB_{start}, RGB_{end}, \frac{t}{T}) RGBcurrent=lerp(RGBstart,RGBend,Tt)


第六章 测试与调试

6.1 自动化测试矩阵

构建参数组合测试:

python 复制代码
test_cases = [
    {'range': (1,10), 'strategy': 'random'},
    {'range': (1,100), 'strategy': 'binary'},
    {'range': (1,1000), 'strategy': 'linear'}
]

6.2 蒙特卡洛测试

进行10,000次模拟运行验证稳定性:

S u c c e s s R a t e = ∑ i = 1 1 0 4 I ( w i n i ) 1 0 4 SuccessRate = \frac{\sum_{i=1}^{10^4} I(win_i)}{10^4} SuccessRate=104∑i=1104I(wini)


结语

通过本文的深度解析,我们揭示了猜数字游戏设计背后复杂的系统工程。从数学公式推导到交互细节打磨,每个环节都体现着软件工程的基本原则。这种经典游戏的设计方法论,可延伸应用于各类交互系统的开发实践。

延伸思考

  • 如何将设计原则迁移到其他猜谜类游戏?
  • 在保证公平性的前提下引入社交元素
  • 基于玩家画像的个性化游戏调整

附录:部分代码

python 复制代码
import sys
import time
import math
import random
from typing import Dict, Any, List, Optional
from PyQt6.QtWidgets import (QApplication, QMainWindow, QPushButton, QLineEdit, 
                           QLabel, QVBoxLayout, QHBoxLayout, QWidget, QSpinBox,
                           QProgressBar, QGroupBox, QGridLayout, QSlider, QMessageBox,
                           QTabWidget, QComboBox, QTextEdit, QRadioButton, QButtonGroup)
from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QThread, QObject
from PyQt6.QtGui import QFont, QColor, QPalette, QIntValidator, QPixmap, QIcon
from game_engine import GameEngine, GameStateManager, GameState
from game_config import GameConfig
from player_analytics import PlayerAnalytics, StrategyType
from advanced_features import InterpolationUtil

class NumberGuessGame(QMainWindow):
    """猜数字游戏GUI主窗口"""
    
    def __init__(self):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("猜数字游戏 - 从数学原理到交互体验")
        self.setMinimumSize(800, 600)
        
        # 初始化游戏配置和引擎
        self.config = GameConfig()
        self.engine = GameEngine(self.config)
        self.analytics = PlayerAnalytics()
        
        # 游戏状态变量
        self.game_active = False
        self.start_time = 0
        self.last_guess_time = 0
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_game_timer)
        
        # 搭建界面
        self.setup_ui()
        
        # 连接信号和槽
        self.connect_signals()
        
        # 准备新游戏
        self.prepare_new_game()
    
    def setup_ui(self):
        """设置用户界面"""
        # 创建中央窗口部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        
        # 标题
        title_label = QLabel("猜数字游戏")
        title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        title_label.setFont(QFont("Arial", 20, QFont.Weight.Bold))
        main_layout.addWidget(title_label)
        
        # 设置选项组
        settings_group = QGroupBox("游戏设置")
        settings_layout = QHBoxLayout()
        
        # 最小值设置
        min_layout = QVBoxLayout()
        min_label = QLabel("最小值:")
        self.min_spinbox = QSpinBox()
        self.min_spinbox.setRange(1, 999)
        self.min_spinbox.setValue(1)
        min_layout.addWidget(min_label)
        min_layout.addWidget(self.min_spinbox)
        settings_layout.addLayout(min_layout)
        
        # 最大值设置
        max_layout = QVBoxLayout()
        max_label = QLabel("最大值:")
        self.max_spinbox = QSpinBox()
        self.max_spinbox.setRange(10, 1000)
        self.max_spinbox.setValue(100)
        max_layout.addWidget(max_label)
        max_layout.addWidget(self.max_spinbox)
        settings_layout.addLayout(max_layout)
        
        # 尝试次数设置
        attempts_layout = QVBoxLayout()
        attempts_label = QLabel("最大尝试次数:")
        self.attempts_spinbox = QSpinBox()
        self.attempts_spinbox.setRange(3, 20)
        self.attempts_spinbox.setValue(7)
        self.attempts_spinbox.setSpecialValueText("自动")  # 表示自动计算最优尝试次数
        attempts_layout.addWidget(attempts_label)
        attempts_layout.addWidget(self.attempts_spinbox)
        settings_layout.addLayout(attempts_layout)
        
        # 难度设置
        difficulty_layout = QVBoxLayout()
        difficulty_label = QLabel("难度:")
        self.difficulty_combo = QComboBox()
        self.difficulty_combo.addItems(["简单", "中等", "困难", "极难"])
        self.difficulty_combo.setCurrentIndex(1)  # 默认中等难度
        difficulty_layout.addWidget(difficulty_label)
        difficulty_layout.addWidget(self.difficulty_combo)
        settings_layout.addLayout(difficulty_layout)
        
        # 设置选项按钮
        options_layout = QVBoxLayout()
        self.dynamic_difficulty_check = QRadioButton("动态难度")
        self.dynamic_difficulty_check.setChecked(True)
        self.fixed_difficulty_check = QRadioButton("固定难度")
        difficulty_group = QButtonGroup(self)
        difficulty_group.addButton(self.dynamic_difficulty_check)
        difficulty_group.addButton(self.fixed_difficulty_check)
        options_layout.addWidget(self.dynamic_difficulty_check)
        options_layout.addWidget(self.fixed_difficulty_check)
        settings_layout.addLayout(options_layout)
        
        # 设置组完成
        settings_group.setLayout(settings_layout)
        main_layout.addWidget(settings_group)
        
        # 游戏状态区域
        game_group = QGroupBox("游戏状态")
        game_layout = QVBoxLayout()
        
        # 当前状态显示
        status_layout = QHBoxLayout()
        self.status_label = QLabel("准备开始")
        self.status_label.setFont(QFont("Arial", 12))
        self.timer_label = QLabel("时间: 0秒")
        self.attempts_label = QLabel("尝试: 0/0")
        status_layout.addWidget(self.status_label)
        status_layout.addStretch()
        status_layout.addWidget(self.timer_label)
        status_layout.addWidget(self.attempts_label)
        game_layout.addLayout(status_layout)
        
        # 范围指示条
        range_layout = QVBoxLayout()
        range_label = QLabel("当前范围:")
        self.range_progress = QProgressBar()
        self.range_progress.setTextVisible(False)
        self.range_min_label = QLabel("1")
        self.range_max_label = QLabel("100")
        range_labels_layout = QHBoxLayout()
        range_labels_layout.addWidget(self.range_min_label)
        range_labels_layout.addStretch()
        range_labels_layout.addWidget(self.range_max_label)
        range_layout.addWidget(range_label)
        range_layout.addWidget(self.range_progress)
        range_layout.addLayout(range_labels_layout)
        game_layout.addLayout(range_layout)
        
        # 输入区域
        input_layout = QHBoxLayout()
        guess_label = QLabel("你的猜测:")
        self.guess_input = QLineEdit()
        self.guess_input.setPlaceholderText("输入一个数字")
        self.guess_input.setValidator(QIntValidator())
        self.guess_button = QPushButton("猜测")
        self.guess_button.setDefault(True)
        input_layout.addWidget(guess_label)
        input_layout.addWidget(self.guess_input)
        input_layout.addWidget(self.guess_button)
        game_layout.addLayout(input_layout)
        
        # 历史记录
        history_layout = QVBoxLayout()
        history_label = QLabel("猜测历史:")
        self.history_text = QTextEdit()
        self.history_text.setReadOnly(True)
        self.history_text.setMaximumHeight(150)
        history_layout.addWidget(history_label)
        history_layout.addWidget(self.history_text)
        game_layout.addLayout(history_layout)
        
        # 提示区域
        hint_layout = QVBoxLayout()
        hint_label = QLabel("提示:")
        self.hint_text = QLabel("使用二分法策略可以最快猜到正确数字")
        self.hint_text.setWordWrap(True)
        self.hint_text.setStyleSheet("color: blue;")
        self.hotness_bar = QProgressBar()
        self.hotness_bar.setRange(0, 10)
        self.hotness_bar.setValue(0)
        hint_layout.addWidget(hint_label)
        hint_layout.addWidget(self.hint_text)
        hint_layout.addWidget(self.hotness_bar)
        game_layout.addLayout(hint_layout)
        
        # 游戏组完成
        game_group.setLayout(game_layout)
        main_layout.addWidget(game_group)
        
        # 按钮区域
        button_layout = QHBoxLayout()
        self.start_button = QPushButton("开始游戏")
        self.new_game_button = QPushButton("新游戏")
        self.statistics_button = QPushButton("查看统计")
        button_layout.addWidget(self.start_button)
        button_layout.addWidget(self.new_game_button)
        button_layout.addWidget(self.statistics_button)
        main_layout.addLayout(button_layout)
        
        # 初始状态设置
        self.new_game_button.setEnabled(False)
        self.guess_button.setEnabled(False)
        self.guess_input.setEnabled(False)
    
    def connect_signals(self):
        """连接信号和槽"""
        self.start_button.clicked.connect(self.start_game)
        self.new_game_button.clicked.connect(self.prepare_new_game)
        self.guess_button.clicked.connect(self.process_guess)
        self.guess_input.returnPressed.connect(self.process_guess)
        self.statistics_button.clicked.connect(self.show_statistics)
        self.difficulty_combo.currentIndexChanged.connect(self.update_difficulty)
        self.min_spinbox.valueChanged.connect(self.update_range)
        self.max_spinbox.valueChanged.connect(self.update_range)
    
    def update_difficulty(self):
        """根据难度设置更新游戏参数"""
        index = self.difficulty_combo.currentIndex()
        
        # 根据难度调整参数
        if index == 0:  # 简单
            self.max_spinbox.setValue(50)
            self.attempts_spinbox.setValue(8)
        elif index == 1:  # 中等
            self.max_spinbox.setValue(100)
            self.attempts_spinbox.setValue(7)
        elif index == 2:  # 困难
            self.max_spinbox.setValue(500)
            self.attempts_spinbox.setValue(9)
        elif index == 3:  # 极难
            self.max_spinbox.setValue(1000)
            self.attempts_spinbox.setValue(10)
    
    def update_range(self):
        """更新范围设置"""
        # 确保最小值比最大值小
        if self.min_spinbox.value() >= self.max_spinbox.value():
            self.max_spinbox.setValue(self.min_spinbox.value() + 10)
        
        # 更新尝试次数 (如果是自动模式)
        if self.attempts_spinbox.value() == 3:  # 特殊值表示自动
            min_val = self.min_spinbox.value()
            max_val = self.max_spinbox.value()
            optimal = math.ceil(math.log2(max_val - min_val + 1))
            self.attempts_spinbox.setValue(optimal)
    
    def prepare_new_game(self):
        """准备新游戏"""
        # 更新UI状态
        self.start_button.setEnabled(True)
        self.new_game_button.setEnabled(False)
        self.guess_button.setEnabled(False)
        self.guess_input.setEnabled(False)
        
        # 清空游戏记录
        self.history_text.clear()
        self.hint_text.setText("使用二分法策略可以最快猜到正确数字")
        self.hotness_bar.setValue(0)
        
        # 更新状态
        self.game_active = False
        self.status_label.setText("准备开始")
        self.timer_label.setText("时间: 0秒")
        self.attempts_label.setText("尝试: 0/0")
        
        # 重置范围条
        min_val = self.min_spinbox.value()
        max_val = self.max_spinbox.value()
        self.range_progress.setRange(min_val, max_val)
        self.range_progress.setValue(min_val)
        self.range_progress.setFormat(f"{min_val} - {max_val}")
        self.range_min_label.setText(str(min_val))
        self.range_max_label.setText(str(max_val))
        
        # 停止计时器
        self.timer.stop()
    
    def start_game(self):
        """开始新游戏"""
        # 更新配置
        self.config.min_number = self.min_spinbox.value()
        self.config.max_number = self.max_spinbox.value()
        self.config.max_attempts = self.attempts_spinbox.value()
        self.config.enable_dynamic_difficulty = self.dynamic_difficulty_check.isChecked()
        
        # 初始化引擎
        self.engine = GameEngine(self.config)
        self.engine.start_new_game()
        
        # 更新UI状态
        self.start_button.setEnabled(False)
        self.new_game_button.setEnabled(True)
        self.guess_button.setEnabled(True)
        self.guess_input.setEnabled(True)
        self.guess_input.setFocus()
        
        # 更新游戏状态
        self.game_active = True
        self.status_label.setText("游戏进行中")
        self.attempts_label.setText(f"尝试: 0/{self.config.max_attempts}")
        
        # 更新范围
        min_val = self.config.min_number
        max_val = self.config.max_number
        self.range_progress.setRange(min_val, max_val)
        self.range_progress.setValue(min_val)
        self.range_min_label.setText(str(min_val))
        self.range_max_label.setText(str(max_val))
        
        # 开始计时
        self.start_time = time.time()
        self.last_guess_time = self.start_time
        self.timer.start(100)  # 100毫秒更新一次
        
        # 清空历史记录
        self.history_text.clear()
        
        # 添加初始提示
        optimal = math.ceil(math.log2(max_val - min_val + 1))
        self.hint_text.setText(f"理论最优猜测次数: {optimal}。首次猜测建议从中间值 {(min_val + max_val) // 2} 开始。")
    
    def process_guess(self):
        """处理用户猜测"""
        if not self.game_active:
            return
            
        # 获取输入
        try:
            guess = int(self.guess_input.text())
        except ValueError:
            self.show_message("错误", "请输入一个有效的整数!")
            self.guess_input.clear()
            return
        
        # 验证猜测
        validation = self.engine.validate_guess(guess)
        if not validation['valid']:
            self.show_message("无效猜测", validation['error'])
            return
        
        # 处理猜测
        feedback = self.engine.process_guess(guess)
        
        # 更新分析系统
        self.analytics.update_strategy_analysis(guess, self.engine.game_state)
        
        # 更新界面
        self.update_ui_after_guess(feedback)
        
        # 清空输入框
        self.guess_input.clear()
        self.guess_input.setFocus()
        
        # 检查游戏是否结束
        if not self.engine.game_state.is_active():
            self.end_game()
    
    def update_ui_after_guess(self, feedback: Dict[str, Any]):
        """猜测后更新UI"""
        guess = feedback['guess']
        diff = feedback['diff']
        attempts = self.engine.game_state.attempts
        max_attempts = self.config.max_attempts
        
        # 更新尝试次数
        self.attempts_label.setText(f"尝试: {attempts}/{max_attempts}")
        
        # 添加历史记录
        history_entry = f"猜测 {attempts}: {guess} "
        if diff == 0:
            history_entry += "✓ 正确!"
            history_entry = f"<span style='color:green; font-weight:bold;'>{history_entry}</span>"
        elif diff > 0:
            history_entry += "↑ 太小了"
            history_entry = f"<span style='color:blue;'>{history_entry}</span>"
        else:
            history_entry += "↓ 太大了"
            history_entry = f"<span style='color:red;'>{history_entry}</span>"
        
        self.history_text.append(history_entry)
        
        # 更新范围条
        curr_min = self.engine.game_state.current_min
        curr_max = self.engine.game_state.current_max
        self.range_min_label.setText(str(curr_min))
        self.range_max_label.setText(str(curr_max))
        
        # 计算动画
        self.animate_range_indicator(curr_min, curr_max)
        
        # 更新提示
        self.update_hints(feedback)
        
        # 计算热度
        self.update_hotness(feedback)
    
    def animate_range_indicator(self, min_val: int, max_val: int):
        """动画更新范围指示条"""
        self.range_progress.setRange(self.config.min_number, self.config.max_number)
        full_range = self.config.max_number - self.config.min_number
        current_range = max_val - min_val
        
        # 计算百分比
        percent_left = (min_val - self.config.min_number) / full_range * 100
        percent_right = (max_val - self.config.min_number) / full_range * 100
        
        # 设置自定义样式
        style = f"""
        QProgressBar::chunk {{
            background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                                           stop:0 transparent,
                                           stop:{percent_left/100} transparent,
                                           stop:{percent_left/100} rgba(0, 120, 210, 200),
                                           stop:{percent_right/100} rgba(0, 120, 210, 200),
                                           stop:{percent_right/100} transparent,
                                           stop:1 transparent);
        }}
        """
        self.range_progress.setStyleSheet(style)
        self.range_progress.setValue(max_val)  # 只是为了触发刷新
    
    def update_hints(self, feedback: Dict[str, Any]):
        """更新提示信息"""
        attempts = self.engine.game_state.attempts
        curr_min = self.engine.game_state.current_min
        curr_max = self.engine.game_state.current_max
        
        # 范围提示始终显示
        range_hint = f"当前范围: {curr_min} - {curr_max},共 {curr_max - curr_min + 1} 个可能的数字。"
        
        # 根据尝试次数提供渐进式提示
        if attempts >= 1 and attempts <= 3:
            # 基本提示
            optimal_guess = (curr_min + curr_max) // 2
            hint = f"{range_hint}<br>二分法建议: 尝试猜测 {optimal_guess}"
            
        elif attempts >= 4 and attempts <= 5:
            # 质数提示
            target = self.engine.game_state.target_number
            if target in self.engine.primes:
                hint = f"{range_hint}<br>提示: 目标数字是一个质数"
            else:
                # 找到最近的质数
                closest_primes = sorted(
                    [p for p in self.engine.primes if curr_min <= p <= curr_max],
                    key=lambda x: abs(x - target)
                )
                if closest_primes:
                    closest = closest_primes[0]
                    diff = abs(closest - target)
                    hint = f"{range_hint}<br>提示: 目标数字距离质数 {closest} 相差 {diff}"
                else:
                    hint = f"{range_hint}<br>提示: 在当前范围内没有质数"
                    
        elif attempts >= 6:
            # 更详细的提示
            target = self.engine.game_state.target_number
            last_guess = feedback['guess']
            
            if target % 2 == 0:
                parity = "偶数"
            else:
                parity = "奇数"
                
            # 提供数字特性提示
            if target < 10:
                size_hint = "个位数"
            elif target < 100:
                size_hint = "两位数"
            else:
                size_hint = "三位数或更大"
                
            hint = f"{range_hint}<br>提示: 目标是一个{parity}。<br>提示: 目标是{size_hint}。"
            
            # 如果还没猜到,给出更多提示
            if attempts >= self.config.max_attempts - 1:
                # 最后的提示
                digit_sum = sum(int(d) for d in str(target))
                hint += f"<br>最终提示: 目标数字的各位数字之和是 {digit_sum}。"
        else:
            hint = range_hint
            
        # 设置提示文本
        self.hint_text.setText(hint)
    
    def update_hotness(self, feedback: Dict[str, Any]):
        """更新热度指示器"""
        # 只有在尝试次数足够时显示热度
        if self.engine.game_state.attempts < 3:
            self.hotness_bar.setValue(0)
            return
            
        target = self.engine.game_state.target_number
        last_guess = feedback['guess']
        
        # 计算温度 (0-10),接近目标温度越高
        max_diff = self.config.max_number - self.config.min_number
        temp = 10 - min(10, int(abs(last_guess - target) / max_diff * 100))
        
        # 设置热度条颜色
        if temp < 3:
            self.hotness_bar.setStyleSheet("QProgressBar::chunk { background-color: blue; }")
        elif temp < 7:
            self.hotness_bar.setStyleSheet("QProgressBar::chunk { background-color: orange; }")
        else:
            self.hotness_bar.setStyleSheet("QProgressBar::chunk { background-color: red; }")
            
        # 设置值
        self.hotness_bar.setValue(temp)
    
    def update_game_timer(self):
        """更新游戏计时器"""
        if not self.game_active:
            return
            
        elapsed = time.time() - self.start_time
        self.timer_label.setText(f"时间: {int(elapsed)}秒")
    
    def end_game(self):
        """结束游戏"""
        self.game_active = False
        self.timer.stop()
        
        # 计算总时间
        total_time = time.time() - self.start_time
        
        # 禁用猜测
        self.guess_button.setEnabled(False)
        self.guess_input.setEnabled(False)
        
        # 更新UI
        if self.engine.game_state.is_won():
            self.status_label.setText("游戏胜利!")
            self.status_label.setStyleSheet("color: green; font-weight: bold;")
            
            # 显示胜利信息
            target = self.engine.game_state.target_number
            attempts = self.engine.game_state.attempts
            message = f"恭喜你猜对了! 目标数字是 {target}。\n"
            message += f"你用了 {attempts} 次尝试,耗时 {total_time:.1f} 秒。\n"
            
            # 评价表现
            optimal = math.ceil(math.log2(self.config.max_number - self.config.min_number + 1))
            if attempts <= optimal:
                message += f"太棒了! 你达到了理论最优解 ({optimal} 次)!"
            elif attempts <= optimal + 2:
                message += f"表现优秀! 接近最优解 ({optimal} 次)!"
            else:
                message += f"还不错! 最优解应该是 {optimal} 次。"
            
            # 检测策略
            strategy = self.analytics.detect_strategy()
            if strategy == StrategyType.BINARY:
                message += "\n\n你使用了二分法策略,这是最有效的策略!"
            elif strategy == StrategyType.LINEAR:
                message += "\n\n你使用了线性搜索策略,试试二分法会更快!"
            elif strategy == StrategyType.RANDOM:
                message += "\n\n你的猜测看起来很随机,有策略会更有效!"
                
        else:
            self.status_label.setText("游戏失败!")
            self.status_label.setStyleSheet("color: red; font-weight: bold;")
            
            # 显示失败信息
            target = self.engine.game_state.target_number
            attempts = self.engine.game_state.attempts
            message = f"很遗憾,你没有猜出正确数字。\n"
            message += f"目标数字是 {target}。\n"
            message += f"你已经尝试了 {attempts} 次,达到了最大尝试次数限制。\n"
            message += "要不要再来一局,尝试使用二分法策略?"
        
        # 显示结果对话框
        QMessageBox.information(self, "游戏结束", message)
        
        # 记录游戏结果
        game_result = {
            'target_number': self.engine.game_state.target_number,
            'attempts': self.engine.game_state.attempts,
            'history': self.engine.game_state.guess_history,
            'duration': total_time,
            'success': self.engine.game_state.is_won(),
            'strategy': self.analytics.detect_strategy()
        }
        
        self.analytics.record_game(game_result)
    
    def show_statistics(self):
        """显示游戏统计数据"""
        stats = self.analytics.get_statistics()
        
        # 构建统计信息
        if stats['total_games'] == 0:
            QMessageBox.information(self, "统计", "还没有游戏记录!")
            return
            
        message = "===== 游戏统计 =====\n\n"
        message += f"总游戏次数: {stats['total_games']}\n"
        message += f"胜率: {stats['win_rate']:.1f}%\n"
        message += f"平均尝试次数: {stats['avg_attempts']:.1f}\n"
        message += f"平均游戏时长: {stats['avg_duration']:.1f}秒\n"
        message += f"检测到的主要策略: {stats['main_strategy']}\n\n"
        
        # 策略分布
        message += "策略分布:\n"
        for strategy, count in stats['strategy_distribution'].items():
            if count > 0:
                message += f"- {strategy}: {count} 次\n"
        
        QMessageBox.information(self, "游戏统计", message)
    
    def show_message(self, title: str, message: str):
        """显示消息对话框"""
        QMessageBox.information(self, title, message)

def main():
    app = QApplication(sys.argv)
    game = NumberGuessGame()
    game.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()
相关推荐
秋名RG8 分钟前
多线程基础:线程创建、启动与生命周期管理
java·开发语言·python
wangbaowo40 分钟前
多种尝试解决Pycharm无法粘贴外部文本【本人问题已解决】
笔记·python·学习·pycharm·生活
大只因bug1 小时前
基于Hadoop大数据技术音乐推荐系统数据分析与可视化(基于Spark和Hive的音乐推荐系统数据分析与可视化)基于Python的音乐推荐系统数据分析与可视化
大数据·hadoop·python·数据分析·spark·音乐推荐系统数据分析可视化·音乐数据分析可实现推荐系统
love530love1 小时前
“100% 成功的 PyTorch CUDA GPU 支持” 安装攻略
人工智能·pytorch·windows·python·深度学习·机器学习
到底怎么取名字不会重复1 小时前
Day15(贪心算法)——LeetCode121.买卖股票的最佳时机&55.跳跃游戏
c++·算法·leetcode·游戏·贪心算法
灏瀚星空2 小时前
随机微分方程(SDE):股票价格模型、利率模型的构建
笔记·python·学习·数学建模·矩阵·开源·量子计算
船长@Quant3 小时前
学习笔记:Qlib 量化投资平台框架 — OTHER COMPONENTS/FEATURES/TOPICS
python·qlib·量化框架
carpell3 小时前
【深度学习基础】:VGG实战篇(图像风格迁移)
人工智能·python·深度学习·计算机视觉
ue星空4 小时前
UE运行游戏时自动播放关卡序列
游戏
一只帆記4 小时前
M1 Mac pip3 install错误记录
python·macos·pip