3、C++项目实战:猜数字游戏(随机数与循环)
猜数字游戏,可以说是编程入门阶段最经典的练手项目之一。别看它简单,里面却藏着C++核心的几块基石:随机数生成、循环控制、条件判断。我当年带新人时,经常让他们从这个小项目开始,因为做完它,你对程序的基本流程控制就有感觉了。
说白了,这个游戏就是程序随机想一个数,你来猜。猜大了提示你大了,猜小了提示你小了,直到猜中为止。嗯,就这么简单。但实现起来,有几个坑你得注意。
3.1 项目需求与功能拆解
我们先明确一下,这个游戏到底要做什么:
- 程序启动后,随机生成一个1到100之间的整数
- 玩家输入猜测的数字
- 程序判断并给出提示:猜大了、猜小了、猜中了
- 猜中后显示猜了多少次
- 询问是否再来一局
你想想看,这个流程其实就是一个典型的“输入-处理-输出”模型。我在项目中处理用户交互逻辑时,也经常用这种模式。
3.2 随机数生成:别踩这个坑
很多新手一上来就写 rand(),然后发现每次运行程序,生成的“随机数”都一样。为什么会这样?
因为 rand() 是伪随机数生成器,它需要一个“种子”。如果不设置种子,默认种子是1,所以每次生成的序列都一样。
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 跳出来更清晰,代码的可读性更好。
3.4 再来一局:外层循环
游戏不能只玩一局就结束吧?我们需要一个外层循环,让玩家可以选择继续或退出。
char playAgain;
do {
// 这里放游戏主逻辑
// ... 生成随机数、猜数字 ...
cout << "是否再来一局?(y/n): ";
cin >> playAgain;
} while (playAgain == 'y' || playAgain == 'Y');
cout << "感谢游玩!再见!" << endl;
这里用 do-while 循环很合适。为什么?因为至少要先玩一局,再问要不要继续。如果用 while,你得在循环外面先问一次,逻辑上就多了一步。
3.5 完整代码与知识图谱
把上面几块拼起来,就是一个完整的猜数字游戏了。我建议你亲手敲一遍,不要复制粘贴。敲代码的过程,就是建立肌肉记忆的过程。
下面这张图,帮你理清整个项目的知识结构:
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,或者加一个“历史猜测记录”的功能。动手改代码,才是最好的学习方式。