第4讲:分支和循环(下)——猜数字游戏实战
第4讲:分支和循环(下)——猜数字游戏实战
掌握了前面学习的 if-else
分支和 while
/for
循环知识后,我们就可以编写一些有趣的小程序了。本节将带你用 C 语言实现一个经典的 “猜数字”游戏。
🎯 游戏需求说明
- 程序自动生成一个 1~100 之间的随机整数。
- 玩家输入猜测的数字。
- 根据玩家输入,提示“猜大了”或“猜小了”,直到猜中为止。
- 可选功能:限制最多只能猜 5 次,超出则失败。
- 支持重复开始新游戏或退出程序。
🔢 一、随机数的生成
要实现这个游戏,关键在于如何生成真正的“随机数”。
使用 rand()
生成伪随机数
C 语言提供了标准库函数 rand()
来生成随机数。
#include <stdlib.h>
int rand(void);
- 功能:返回一个范围在
0
到RAND_MAX
之间的伪随机整数。 RAND_MAX
是宏定义,在大多数编译器中为32767
。
示例:测试 rand()
#include <stdio.h>
#include <stdlib.h>int main() {printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;
}
⚠️ 注意:每次运行程序时,输出的随机数序列都相同!这是因为
rand()
使用的是固定的“种子”(seed),默认值为 1。
使用 srand()
设置种子
为了使每次运行程序都能得到不同的随机数序列,我们需要使用 srand()
函数来设置不同的“种子”。
#include <stdlib.h>
void srand(unsigned int seed);
- 参数
seed
是随机数生成器的起始值。 - 只要
seed
不同,rand()
产生的序列就不同。
❌ 错误示例:固定种子
srand(1); // 每次种子都是1 → 随机数序列永远相同
✅ 正确做法:使用变化的种子
理想情况下,种子应该是每次运行都不一样的值,比如当前时间。
使用 time()
获取当前时间作为种子
#include <time.h>
time_t time(time_t *timer);
- 返回自 1970年1月1日0时0分0秒(UTC) 起到现在的秒数(称为“时间戳”)。
- 如果传入
NULL
,直接返回时间戳。
我们将 time(NULL)
的返回值作为 srand()
的参数:
srand((unsigned int)time(NULL));
✅ 这样每次运行程序时,由于时间不同,种子也不同,从而产生不同的随机数序列。
📌 重要提醒:
srand()
应该在整个程序中只调用一次!通常放在main()
函数开头。- 多次调用
srand()
反而可能导致随机性变差。
控制随机数范围
rand()
默认生成的是 0 ~ RAND_MAX
的数,但我们想要的是 1 ~ 100
。
常见技巧:取模运算 %
目标范围 | 表达式 | 说明 |
---|---|---|
0 ~ 99 | rand() % 100 | 取余结果为 0~99 |
1 ~ 100 | rand() % 100 + 1 | 加1后变为 1~100 ✅ |
a ~ b | a + rand() % (b - a + 1) | 通用公式 |
✅ 所以我们要生成 1~100 的随机数:
int secret = rand() % 100 + 1;
🎮 二、猜数字游戏实现
下面我们逐步构建完整的猜数字游戏。
基础版本(无限次猜测)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>// 游戏主逻辑
void game() {int secret = rand() % 100 + 1; // 生成1~100的随机数int guess = 0;while (1) {printf("请猜数字>: ");scanf("%d", &guess);if (guess < secret) {printf("猜小了!\n");} else if (guess > secret) {printf("猜大了!\n");} else {printf("🎉 恭喜你,猜对了!答案就是 %d\n", secret);break; // 结束游戏}}
}// 显示菜单
void menu() {printf("***********************\n");printf("****** 1. 开始游戏 ******\n");printf("****** 0. 退出游戏 ******\n");printf("***********************\n");
}// 主函数
int main() {int input = 0;// 初始化随机种子(仅需一次)srand((unsigned int)time(NULL));do {menu();printf("请选择:> ");scanf("%d", &input);switch (input) {case 1:game();break;case 0:printf("🎮 游戏结束,欢迎下次再来!\n");break;default:printf("❌ 输入错误,请重新选择!\n");break;}} while (input != 0); // 当用户选择0时退出return 0;
}
升级版:增加猜测次数限制(5次机会)
我们可以加入计数器,最多允许猜 5 次,失败则显示正确答案。
void game() {int secret = rand() % 100 + 1;int guess = 0;int count = 5; // 最多5次机会printf("🎯 游戏开始!你有 %d 次机会猜1~100之间的数字。\n", count);while (count > 0) {printf("\n你还有 %d 次机会\n", count);printf("请猜数字>: ");scanf("%d", &guess);if (guess == secret) {printf("🎉 恭喜你,猜对了!答案是 %d\n", secret);break;} else if (guess < secret) {printf("🔺 猜小了!\n");} else {printf("🔻 猜大了!\n");}count--; // 消耗一次机会}if (count == 0) {printf("💔 很遗憾,你的机会用完了!正确答案是:%d\n", secret);}
}
✅ 总结与知识点回顾
知识点 | 作用说明 |
---|---|
rand() | 生成伪随机数(0 ~ RAND_MAX) |
srand(seed) | 设置随机数种子,改变序列起点 |
time(NULL) | 获取当前时间戳(秒级),常作种子 |
rand() % N + M | 将随机数限定在 M ~ M+N-1 范围内 |
do-while 循环 | 实现菜单循环选择 |
switch-case | 处理用户菜单选项 |
💡 小贴士
- 不要频繁调用
srand()
,否则可能因时间精度问题导致种子重复。 - 在调试程序时,可暂时使用固定种子(如
srand(123);
)以便复现问题。 - 若希望更安全的随机性,现代C++推荐使用
<random>
库,但在C语言中rand()+time()
已足够教学和简单项目使用。
🏁 结语
通过这个小游戏,我们综合运用了:
- 分支结构(
if-else
,switch
) - 循环控制(
while
,do-while
) - 函数封装(
game()
,menu()
) - 标准库使用(
stdlib.h
,time.h
)
这是第一个真正意义上的“交互式程序”,标志着你已迈入编程实践的大门!
继续加油,下一个目标:石头剪刀布游戏 or 简易计算器!