3、C++项目实战:猜数字游戏(随机数与循环)

猜数字游戏,可以说是编程入门阶段最经典的练手项目之一。别看它简单,里面却藏着C++核心的几块基石:随机数生成、循环控制、条件判断。我当年带新人时,经常让他们从这个小项目开始,因为做完它,你对程序的基本流程控制就有感觉了。

说白了,这个游戏就是程序随机想一个数,你来猜。猜大了提示你大了,猜小了提示你小了,直到猜中为止。嗯,就这么简单。但实现起来,有几个坑你得注意。

3.1 项目需求与功能拆解

我们先明确一下,这个游戏到底要做什么:

  • 程序启动后,随机生成一个1到100之间的整数
  • 玩家输入猜测的数字
  • 程序判断并给出提示:猜大了、猜小了、猜中了
  • 猜中后显示猜了多少次
  • 询问是否再来一局

你想想看,这个流程其实就是一个典型的“输入-处理-输出”模型。我在项目中处理用户交互逻辑时,也经常用这种模式。

3.2 随机数生成:别踩这个坑

很多新手一上来就写 rand(),然后发现每次运行程序,生成的“随机数”都一样。为什么会这样?

因为 rand() 是伪随机数生成器,它需要一个“种子”。如果不设置种子,默认种子是1,所以每次生成的序列都一样。

我曾经踩过的坑: 刚学C++时,我用了 srand(time(0)) 来设置种子,但在一秒内多次调用程序,生成的数还是相同。因为 time(0) 返回的是秒级时间戳,同一秒内调用,种子一样。

正确的做法是:

#include <iostream>
#include <cstdlib>   // rand() 和 srand()
#include <ctime>     // time()
using namespace std;

int main() {
    // 设置随机种子,只设置一次
    srand(static_cast<unsigned int>(time(0)));
    
    // 生成1到100之间的随机数
    int secretNumber = rand() % 100 + 1;
    
    cout << "猜数字游戏开始!范围:1-100" << endl;
    
    return 0;
}

这里有个细节:rand() % 100 生成的是0到99,加1后变成1到100。我个人习惯用 static_cast<unsigned int> 做类型转换,这样更安全,编译器不会报警告。

3.3 循环控制:让游戏跑起来

游戏的核心是一个循环。玩家猜一次,程序判断一次,没猜中就继续。这里用 while 循环最合适:

int guess;
int attempts = 0;
bool guessed = false;

while (!guessed) {
    cout << "请输入你的猜测:";
    cin >> guess;
    attempts++;
    
    if (guess > secretNumber) {
        cout << "猜大了!再试试。" << endl;
    } else if (guess < secretNumber) {
        cout << "猜小了!再试试。" << endl;
    } else {
        cout << "恭喜你!猜中了!" << endl;
        cout << "你一共猜了 " << attempts << " 次。" << endl;
        guessed = true;
    }
}

注意看,我用了一个 bool 变量 guessed 来控制循环。当猜中时,把它设为 true,循环自然结束。这种做法比用 break 跳出来更清晰,代码的可读性更好。

小技巧: 如果你想让游戏更有挑战性,可以限制最大猜测次数。比如10次猜不中就失败。我在做教学项目时,经常加这个限制,让学生体会“有限循环”和“无限循环”的区别。

3.4 再来一局:外层循环

游戏不能只玩一局就结束吧?我们需要一个外层循环,让玩家可以选择继续或退出。

char playAgain;
do {
    // 这里放游戏主逻辑
    // ... 生成随机数、猜数字 ...
    
    cout << "是否再来一局?(y/n): ";
    cin >> playAgain;
} while (playAgain == 'y' || playAgain == 'Y');

cout << "感谢游玩!再见!" << endl;

这里用 do-while 循环很合适。为什么?因为至少要先玩一局,再问要不要继续。如果用 while,你得在循环外面先问一次,逻辑上就多了一步。

3.5 完整代码与知识图谱

把上面几块拼起来,就是一个完整的猜数字游戏了。我建议你亲手敲一遍,不要复制粘贴。敲代码的过程,就是建立肌肉记忆的过程。

下面这张图,帮你理清整个项目的知识结构:

猜数字游戏知识结构图 猜数字游戏 随机数生成 循环控制 条件判断 srand() + time(0) 设置种子 rand() % N + 1 生成范围 while 循环:猜中为止 do-while 循环:再来一局 if-else if-else 判断大小 bool 变量控制循环结束 核心思想:输入 → 处理 → 输出 用循环处理重复,用条件处理分支

3.6 完整代码示例

好了,我把所有代码整合在一起。你直接复制到IDE里就能跑:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    srand(static_cast<unsigned int>(time(0)));
    char playAgain;
    
    do {
        int secretNumber = rand() % 100 + 1;
        int guess;
        int attempts = 0;
        bool guessed = false;
        
        cout << "\n=== 猜数字游戏 ===" << endl;
        cout << "我已经想好了一个1-100之间的数字。" << endl;
        
        while (!guessed) {
            cout << "请输入你的猜测:";
            cin >> guess;
            attempts++;
            
            if (guess > secretNumber) {
                cout << "猜大了!" << endl;
            } else if (guess < secretNumber) {
                cout << "猜小了!" << endl;
            } else {
                cout << "恭喜你!猜中了!" << endl;
                cout << "你一共猜了 " << attempts << " 次。" << endl;
                guessed = true;
            }
        }
        
        cout << "是否再来一局?(y/n): ";
        cin >> playAgain;
    } while (playAgain == 'y' || playAgain == 'Y');
    
    cout << "感谢游玩,再见!" << endl;
    return 0;
}

3.7 避坑指南与经验总结

做这个项目,有几个地方容易出问题,我帮你列出来:

  • 随机数种子只设置一次srand() 放在循环外面,否则每次生成的随机数可能重复。
  • 输入验证:如果玩家输入了字母或特殊字符,cin 会进入错误状态。我在项目中遇到过这种情况,后来加了 cin.clear()cin.ignore() 来处理。
  • 变量初始化attempts 记得初始化为0,guessed 初始化为 false。不初始化的话,变量里的值是垃圾数据。

核心收获: 做完这个项目,你应该掌握三件事——如何生成随机数、如何用循环控制程序流程、如何用条件判断做分支。这三板斧,在后面的项目中会反复用到。

嗯,这个项目就讲到这里。代码不多,但值得你反复推敲。试着改一改,比如把范围改成1到1000,或者加一个“历史猜测记录”的功能。动手改代码,才是最好的学习方式。


公众号:蓝海资料掘金营,微信deep3321