欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/xiaomei11/shangpinjiage

在这里插入图片描述
在这里插入图片描述

🎁 商品猜价格游戏 - 完整技术实现指南

一、项目概述

商品猜价格是一个互动式网页游戏,用户通过猜测商品价格获取分数。游戏包含5轮挑战,每轮最多10次猜测机会,根据猜测次数计算得分,鼓励用户用最少的次数猜中价格。

1.1 系统架构设计

┌─────────────────────────────────────────────────────────────┐
│                    商品猜价格游戏系统                        │
├─────────────────────────────────────────────────────────────┤
│                    UI层 (index.html)                        │
│  ┌─────────────┬─────────────┬─────────────┬─────────────┐  │
│  │  商品展示区  │  猜测输入区 │  提示反馈区 │  历史记录区 │  │
│  └─────────────┴─────────────┴─────────────┴─────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                  业务逻辑层 (app.js)                         │
│  ┌────────────┬────────────┬────────────┬────────────┐    │
│  │  游戏管理   │  商品管理   │  分数计算   │  状态管理   │    │
│  └────────────┴────────────┴────────────┴────────────┘    │
├─────────────────────────────────────────────────────────────┤
│                  数据持久层 (LocalStorage)                   │
│  ┌──────────────────────────────────────────────────────┐ │
│  │         guessPriceHighScore (最高分)                 │ │
│  └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

1.2 核心功能模块

模块 功能描述 技术要点
游戏控制 游戏开始、结束、重新开始、下一轮 状态管理、流程控制
商品管理 商品数据、随机抽取、去重机制 数据结构、随机算法
猜测验证 价格比较、智能提示 数值计算、条件判断
分数系统 基础分、惩罚分、奖励分 算法设计、策略优化
历史记录 猜测历史、颜色标记 DOM操作、动态渲染
数据持久化 最高分保存 LocalStorage操作

二、数据模型设计

2.1 商品数据结构

{
    id: 1,                          // 唯一标识
    name: '无线蓝牙耳机',            // 商品名称
    desc: '高品质音质,降噪功能,续航20小时',  // 商品描述
    price: 299,                     // 商品价格
    icon: '🎧'                      // 商品图标
}

设计要点:

  • id:使用自增数字ID,便于随机抽取和去重
  • name:清晰的商品名称
  • desc:详细的商品描述,帮助用户了解商品价值
  • price:整数价格,便于比较
  • icon:使用Emoji图标,视觉友好

2.2 商品库示例

系统内置20种精心挑选的商品,价格范围从29元到2199元,涵盖数码产品和生活用品:

ID 商品名称 价格 图标
1 无线蓝牙耳机 ¥299 🎧
2 智能运动手表 ¥499
3 便携充电宝 ¥89 🔋
4 机械键盘 ¥199 ⌨️
5 无线鼠标 ¥59 🖱️
6 平板电脑 ¥2199 📱
7 游戏手柄 ¥159 🎮
8 降噪耳机 ¥399 🎵
9 智能台灯 ¥129 💡
10 保温杯 ¥79 🥤
11 笔记本电脑支架 ¥89 💻
12 USB-C扩展坞 ¥149 🔌
13 蓝牙音箱 ¥169 🔊
14 智能体重秤 ¥99 ⚖️
15 电动牙刷 ¥139 🪥
16 空气净化器 ¥599 🌬️
17 瑜伽垫 ¥69 🧘
18 运动水杯 ¥39 💧
19 健身手套 ¥45 🧤
20 跳绳 ¥29 🪢

2.3 游戏状态结构

{
    products: [...],               // 商品库
    currentProduct: null,          // 当前商品
    guessHistory: [],              // 猜测历史
    score: 0,                      // 当前得分
    attempts: 10,                  // 剩余尝试次数
    round: 1,                      // 当前轮数
    maxRounds: 5,                  // 最大轮数
    highScore: 0,                  // 最高分
    isGameActive: false,           // 游戏是否进行中
    isRoundComplete: false,        // 当前轮是否完成
    usedProducts: []               // 已使用的商品ID
}

三、核心代码实现详解

3.1 游戏类的设计与初始化

class GuessPriceGame {
    constructor() {
        this.products = this.getProductData();
        this.currentProduct = null;
        this.guessHistory = [];
        this.score = 0;
        this.attempts = 10;
        this.round = 1;
        this.maxRounds = 5;
        this.highScore = 0;
        this.isGameActive = false;
        this.isRoundComplete = false;
        this.usedProducts = [];
        this.init();
    }

    init() {
        this.loadHighScore();
        this.initDOMReferences();
        this.bindEventListeners();
        this.renderProductGrid();
        this.updateStatusDisplay();
    }
}

核心设计要点:

  • 构造函数:初始化所有游戏状态
  • init方法:按顺序执行初始化流程
  • 职责分离:每个方法负责单一功能

3.2 商品随机抽取算法

getRandomProduct() {
    const availableProducts = this.products.filter(p => 
        !this.usedProducts.includes(p.id)
    );
    
    if (availableProducts.length === 0) {
        this.usedProducts = [];
        return this.products[Math.floor(Math.random() * this.products.length)];
    }
    
    const product = availableProducts[
        Math.floor(Math.random() * availableProducts.length)
    ];
    this.usedProducts.push(product.id);
    return product;
}

算法分析:

  1. 过滤已使用商品:确保不重复使用相同商品
  2. 边界处理:商品库用尽时重置usedProducts
  3. 随机选择:使用Math.random()和数组索引实现
  4. 状态更新:将选中的商品ID加入已使用列表

时间复杂度: O(n),n为商品库大小

3.3 分数计算算法

calculateScore(attemptsUsed) {
    const baseScore = 100;               // 基础分
    const penalty = attemptsUsed * 8;    // 惩罚分
    const bonus = attemptsUsed <= 3 ? 50 : (attemptsUsed <= 6 ? 25 : 0);  // 奖励分
    return Math.max(baseScore - penalty + bonus, 10);  // 保底10分
}

分数计算策略:

尝试次数 基础分 惩罚分 奖励分 最终得分
1 100 -8 +50 142
2 100 -16 +50 134
3 100 -24 +50 126
4 100 -32 +25 93
5 100 -40 +25 85
6 100 -48 +25 77
7 100 -56 0 44
8 100 -64 0 36
9 100 -72 0 28
10 100 -80 0 20
>10 100 -80 0 10

设计优势:

  • 鼓励快速猜中,早期奖励丰厚
  • 后期惩罚递增,但保证有得分
  • 设置最低分,避免负分

3.4 智能提示系统

handleWrongGuess(guess, actualPrice) {
    const diff = Math.abs(guess - actualPrice);
    let hint;
    
    if (diff > actualPrice * 0.5) {
        hint = guess > actualPrice ? 
            '太高了!猜低一点' : '太低了!猜高一点';
    } else if (diff > actualPrice * 0.2) {
        hint = guess > actualPrice ? 
            '有点高,再低一些' : '有点低,再高一些';
    } else {
        hint = guess > actualPrice ? 
            '接近了!再低一点点' : '接近了!再高一点点';
    }
    
    this.hintMessage.textContent = hint;
    this.hintMessage.className = 
        `hint-message ${guess > actualPrice ? 'high' : 'low'}`;
    this.guessInput.value = '';
    this.guessInput.focus();
}

提示级别设计:

误差范围 提示内容 视觉反馈
>50% 太高了!猜低一点 / 太低了!猜高一点 红色/绿色
20%-50% 有点高,再低一些 / 有点低,再高一些 红色/绿色
<20% 接近了!再低一点点 / 接近了!再高一点点 红色/绿色

动态UI反馈:

  • 根据猜测方向应用不同的CSS类
  • 自动清空输入框
  • 自动聚焦输入框,提升体验

3.5 游戏流程控制

startGame() {
    this.score = 0;
    this.attempts = 10;
    this.round = 1;
    this.usedProducts = [];
    this.isGameActive = true;
    this.startNewRound();
    
    this.startBtn.style.display = 'none';
    this.restartBtn.style.display = 'inline-block';
    this.guessBtn.disabled = false;
    this.showToast('游戏开始!加油!', 'success');
}

startNewRound() {
    this.currentProduct = this.getRandomProduct();
    this.guessHistory = [];
    this.attempts = 10;
    this.isRoundComplete = false;
    
    this.productImageEl.innerHTML = 
        `<span class="placeholder">${this.currentProduct.icon}</span>`;
    this.productNameEl.textContent = this.currentProduct.name;
    this.productDescEl.textContent = this.currentProduct.desc;
    this.guessInput.value = '';
    this.hintMessage.textContent = '猜猜这个商品的价格?';
    this.hintMessage.className = 'hint-message';
    this.historyList.innerHTML = '';
    this.guessBtn.disabled = false;
    this.nextBtn.style.display = 'none';
    this.updateStatusDisplay();
    this.guessInput.focus();
}

nextProduct() {
    this.round++;
    
    if (this.round > this.maxRounds) {
        this.endGame();
        return;
    }
    
    this.startNewRound();
    this.showToast(`${this.round} 轮开始!`, 'success');
}

状态转换流程:

初始化 → 开始游戏 → 第1轮 → 猜测 → 猜对/次数用完 → 
       ↓
    第2轮 → 猜测 → ... → 第5轮 → 游戏结束 → 显示结果

3.6 猜测验证处理

makeGuess() {
    if (!this.isGameActive || this.isRoundComplete) return;
    
    const guess = parseFloat(this.guessInput.value);
    if (isNaN(guess) || guess < 0) {
        this.showToast('请输入有效的价格', 'warning');
        return;
    }
    
    const actualPrice = this.currentProduct.price;
    this.guessHistory.push(guess);
    this.attempts--;
    this.updateStatusDisplay();
    this.addHistoryItem(guess, actualPrice);
    
    if (guess === actualPrice) {
        this.handleCorrectGuess();
    } else if (this.attempts === 0) {
        this.handleNoMoreAttempts();
    } else {
        this.handleWrongGuess(guess, actualPrice);
    }
}

验证流程:

  1. 检查游戏状态
  2. 验证输入合法性
  3. 更新猜测历史
  4. 减少尝试次数
  5. 根据猜测结果分发处理

3.7 游戏结束处理

endGame() {
    this.isGameActive = false;
    this.guessBtn.disabled = true;
    this.nextBtn.style.display = 'none';
    this.startBtn.style.display = 'inline-block';
    
    const isNewRecord = this.score > this.highScore;
    if (isNewRecord) {
        this.highScore = this.score;
        this.saveHighScore();
        this.updateStatusDisplay();
    }
    
    this.showGameOverModal(isNewRecord);
}

showGameOverModal(isNewRecord) {
    this.finalScore.textContent = this.score;
    
    if (isNewRecord) {
        this.finalMessage.textContent = '🎊 新纪录!太棒了!';
    } else if (this.score >= 400) {
        this.finalMessage.textContent = '🏆 非常优秀!';
    } else if (this.score >= 250) {
        this.finalMessage.textContent = '👍 表现不错!';
    } else if (this.score >= 100) {
        this.finalMessage.textContent = '💪 继续加油!';
    } else {
        this.finalMessage.textContent = '🌱 多多练习!';
    }
    
    this.gameOverModal.classList.add('active');
}

评价体系:

得分范围 评价 表情
新纪录 新纪录!太棒了! 🎊
≥400 非常优秀! 🏆
250-399 表现不错! 👍
100-249 继续加油! 💪
<100 多多练习! 🌱

3.8 LocalStorage数据持久化

loadHighScore() {
    const saved = localStorage.getItem('guessPriceHighScore');
    if (saved) {
        this.highScore = parseInt(saved) || 0;
    }
}

saveHighScore() {
    localStorage.setItem('guessPriceHighScore', this.highScore.toString());
}

数据持久化要点:

  • 使用localStorage.setItem()保存数据
  • 使用localStorage.getItem()读取数据
  • 数据类型转换:数字存储为字符串,读取时解析
  • 容错处理:parseInt()失败时返回0

四、UI交互设计

4.1 响应式布局设计

.game-board {
    background: rgba(255, 255, 255, 0.95);
    border-radius: 20px;
    padding: 30px;
    box-shadow: 0 8px 35px rgba(0, 0, 0, 0.2);
    margin-bottom: 30px;
}

.product-display {
    display: flex;
    gap: 30px;
    margin-bottom: 30px;
    align-items: center;
}

@media (max-width: 768px) {
    .header h1 {
        font-size: 2rem;
    }

    .product-display {
        flex-direction: column;
        text-align: center;
    }

    .product-image {
        width: 150px;
        height: 150px;
    }

    .status-bar {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .status-bar {
        grid-template-columns: 1fr;
    }
}

响应式断点:

设备类型 断点 布局策略
桌面端 >768px 横向布局,4列状态
平板端 480-768px 纵向布局,2列状态
移动端 <480px 单列布局,1列状态

4.2 视觉主题设计

body {
    background: linear-gradient(135deg, 
        #667eea 0%, 
        #764ba2 50%, 
        #f093fb 100%);
}

.hint-message.high {
    background: #fff5f5;
    color: #c53030;
}

.hint-message.low {
    background: #f0fff4;
    color: #276749;
}

.hint-message.correct {
    background: #fffbea;
    color: #b7791f;
}

配色方案:

用途 颜色 含义
背景渐变 #667eea → #f093fb 活力、游戏感
猜高提示 #fff5f5 / #c53030 红色警告
猜低提示 #f0fff4 / #276749 绿色通过
猜对提示 #fffbea / #b7791f 黄色警告

4.3 按钮状态管理

.guess-btn {
    padding: 18px 40px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: #fff;
    border: none;
    border-radius: 12px;
    font-size: 1.1rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
}

.guess-btn:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}

.guess-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

状态设计:

  • 默认状态:渐变背景,正常样式
  • 悬停状态:向上移动2px,添加阴影
  • 禁用状态:透明度0.5,不可点击

4.4 Toast消息提示

showToast(message, type = 'success') {
    this.toastMessage.textContent = message;
    this.toast.className = 'toast';
    if (type) this.toast.classList.add(type);
    this.toast.classList.add('show');
    
    setTimeout(() => {
        this.toast.classList.remove('show');
    }, 2500);
}
.toast {
    position: fixed;
    bottom: 30px;
    left: 50%;
    transform: translateX(-50%) translateY(100px);
    background: #333;
    color: #fff;
    padding: 14px 30px;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    z-index: 2000;
    opacity: 0;
    transition: all 0.3s ease;
}

.toast.show {
    transform: translateX(-50%) translateY(0);
    opacity: 1;
}

动画效果:

  • 从底部滑入,2500ms后滑出
  • 支持三种类型:success、warning、error
  • 居中显示,固定定位

五、性能优化策略

5.1 DOM引用缓存

initDOMReferences() {
    this.productImageEl = document.getElementById('productImage');
    this.productNameEl = document.getElementById('productName');
    this.productDescEl = document.getElementById('productDesc');
    this.guessInput = document.getElementById('guessInput');
    this.guessBtn = document.getElementById('guessBtn');
    this.hintMessage = document.getElementById('hintMessage');
    this.historyList = document.getElementById('historyList');
    this.scoreValue = document.getElementById('scoreValue');
    this.attemptsValue = document.getElementById('attemptsValue');
    this.roundValue = document.getElementById('roundValue');
    this.highScoreValue = document.getElementById('highScoreValue');
    // ... 更多引用
}

优化效果:

  • 避免重复调用getElementById()
  • 减少DOM查询开销
  • 提升渲染性能

5.2 事件绑定优化

bindEventListeners() {
    this.startBtn.addEventListener('click', () => this.startGame());
    this.nextBtn.addEventListener('click', () => this.nextProduct());
    this.restartBtn.addEventListener('click', () => this.restartGame());
    this.guessBtn.addEventListener('click', () => this.makeGuess());
    
    this.guessInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter' && this.isGameActive && !this.isRoundComplete) {
            this.makeGuess();
        }
    });
}

优化要点:

  • 使用箭头函数确保this上下文正确
  • 条件判断避免不必要的函数调用
  • 支持键盘操作(Enter键)

5.3 渲染优化

renderProductGrid() {
    this.productGrid.innerHTML = this.products.map(product => `
        <div class="product-card">
            <div class="product-card-icon">${product.icon}</div>
            <div class="product-card-name">${product.name}</div>
            <div class="product-card-price">¥${product.price}</div>
        </div>
    `).join('');
}

优化策略:

  • 使用innerHTML一次性渲染,而不是多次DOM操作
  • 使用模板字符串和map()构建HTML
  • 避免在循环中进行DOM操作

六、扩展性设计

6.1 商品数据扩展

只需修改getProductData()方法即可添加新商品:

getProductData() {
    return [
        { id: 1, name: '无线蓝牙耳机', desc: '...', price: 299, icon: '🎧' },
        { id: 2, name: '智能运动手表', desc: '...', price: 499, icon: '⌚' },
        // 添加新商品...
    ];
}

6.2 游戏规则扩展

可以轻松调整游戏参数:

constructor() {
    this.attempts = 10;        // 可改为8、15等
    this.maxRounds = 5;        // 可改为3、10等
    // ... 其他参数
}

calculateScore(attemptsUsed) {
    const baseScore = 100;     // 可调整
    const penalty = attemptsUsed * 8;  // 可调整惩罚系数
    const bonus = attemptsUsed <= 3 ? 50 : (attemptsUsed <= 6 ? 25 : 0);
    return Math.max(baseScore - penalty + bonus, 10);
}

6.3 UI主题扩展

支持自定义主题色,只需修改CSS变量或渐变:

body {
    background: linear-gradient(135deg, 
        #your-color-1 0%, 
        #your-color-2 50%, 
        #your-color-3 100%);
}

七、测试与验证

7.1 功能测试用例

测试场景 输入 预期结果
开始游戏 点击"开始游戏" 显示第一个商品,分数0,轮数1,次数10
正确猜测 输入正确价格 显示"恭喜答对",加分,显示下一轮按钮
错误猜测 输入错误价格 显示提示,次数减1,添加历史记录
次数用尽 10次都猜错 显示正确答案,显示下一轮按钮
游戏结束 完成5轮 显示最终得分,保存最高分
新纪录 得分超过历史最高 显示"新纪录",更新最高分
重新开始 点击"重新开始" 重置所有状态

7.2 边界条件测试

测试场景 测试内容 预期结果
空输入 不输入直接提交 提示"请输入有效的价格"
负数输入 输入负数 提示"请输入有效的价格"
输入非数字 输入文字 提示"请输入有效的价格"
最高分存储 刷新页面 最高分保持不变
商品去重 连续游戏 不重复出现相同商品

7.3 响应式测试

设备尺寸 测试内容
1920x1080 完整显示所有内容
1024x768 正常显示,无错位
768x1024 响应式布局,2列状态
375x667 单列布局,正常交互

八、总结

商品猜价格游戏通过精心设计的游戏机制和完整的实现,提供了一个有趣且易用的互动体验。

核心优势

  1. 完整的游戏流程:从开始到结束,流畅完整
  2. 智能提示系统:根据误差程度给出不同提示
  3. 合理的分数计算:鼓励快速猜中,奖励策略合理
  4. 数据持久化:自动保存最高分
  5. 响应式设计:支持各种设备
  6. 可扩展性强:易于添加新商品和调整规则

技术亮点

  • 面向对象设计:使用Class组织代码,结构清晰
  • DOM引用缓存:优化性能
  • LocalStorage持久化:数据保存
  • 智能随机算法:商品去重抽取
  • 状态管理:完整的游戏状态控制
  • 响应式布局:CSS Grid + Flexbox

未来扩展方向

  1. 更多商品:增加商品库到50种
  2. 难度选择:简单/普通/困难模式
  3. 排行榜:与朋友分享分数
  4. 音效:添加背景音乐和音效
  5. 动画:更丰富的交互动画
  6. 后台管理:商品库编辑功能
  7. 联机对战:多人实时对战模式

附录:游戏策略指南

A.1 猜价格技巧

  1. 观察商品描述:仔细阅读商品描述,了解商品价值
  2. 从中间价位开始:先猜一个中间价格,快速缩小范围
  3. 使用二分法:每次猜区间中间值,快速定位
  4. 参考商品库:查看下方商品库,了解价格区间
  5. 保留猜测历史:查看历史记录,分析趋势

A.2 满分攻略

要获得高分(每轮都在前3次猜中):

  1. 熟悉常见商品价格
  2. 每次猜测后仔细分析提示
  3. 使用二分法策略
  4. 保持冷静,不要急躁
  5. 多练习,提高价格敏感度

A.3 预期得分参考

每轮平均尝试次数 预期总得分 评价
1-2次 600-700分 天才级别!
3次 500-600分 非常优秀!
4-5次 350-500分 表现不错!
6-8次 200-350分 继续加油!
>8次 <200分 多多练习!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐