← 课程目录
第 10 讲 模块三:让程序重复执行

实战:猜数字游戏

10 / 24
💡
本节课目标
今天不学大块新语法,只补一个小工具——随机数, 然后把模块二的条件判断和模块三的循环拼成一个能玩的游戏: 电脑随机想一个数,你来猜,它提示“大了 / 小了”,限定次数内猜中就赢。
开场

循环 + 条件,能做什么

📖 理论讲解

模块三回顾

第 8 讲 while:次数看运行情况的循环。 第 9 讲 forbreak / continue:次数已知的循环,以及中途跳出。

猜数字游戏正好把它们全用上:反复让玩家猜(循环), 每次判断大了还是小了(条件),猜中就跳出break)。

需求

游戏规则

📖 理论讲解

说清楚要做什么

  • 程序随机生成一个 1~100 的整数,作为答案。
  • 玩家最多猜 7 次
  • 每次猜完,提示“大了”“小了”
  • 猜中:祝贺并告知用了几次,游戏结束。
  • 次数用完还没中:公布答案,游戏结束。
新工具

让电脑“想”一个数:随机数

📖 理论讲解

rand()、srand() 和种子

C++ 用 rand() 产生随机整数,它在 <cstdlib> 里。 但 rand() 其实是“伪随机”——不设置种子的话,每次运行都得到同一串数。

所以先用 srand(time(0))当前时间做种子(time()<ctime> 里)。时间每秒都在变,每次运行的随机数就不一样了。

random_demo.cpp CPP
#include <iostream>
#include <cstdlib>   // rand()、srand()
#include <ctime>     // time()

int main() {
    srand(time(0));            // 用当前时间做“种子”,每次运行都不一样
    int answer = rand() % 100 + 1;   // 1 ~ 100 之间的随机整数
    std::cout << "(偷偷告诉你,答案是 " << answer << ")" << std::endl;
    return 0;
}
rand() % 100 + 1 怎么来的
rand() % 100 取余,结果落在 0~99;再 + 1 就变成 1~100。想要 1~6 的骰子,就写 rand() % 6 + 1—— % 后面的数 = 范围大小,+ 后面的数 = 起点
⚠️
srand 只调用一次
srand(time(0)) 写在 main 开头一次就够了。 如果放进循环里反复 srand,同一秒内种子相同,反而可能连续生成一样的数。
设计

先搭骨架,再填血肉

📖 理论讲解

循环 + 三路判断

核心是一个循环,循环体里对这次的 guess 做三种判断: 偏大、偏小、正好。先用伪代码把骨架想清楚:

skeleton.txt CPP
int answer = rand() % 100 + 1;
int guess;

while (??) {              // 还没猜中、且次数没用完,就继续
    std::cin >> guess;

    if (guess > answer) {
        std::cout << "大了" << std::endl;
    } else if (guess < answer) {
        std::cout << "小了" << std::endl;
    } else {
        // 猜中了,该怎么办?
    }
}

两个待定的地方:循环什么时候停(猜中、或次数用完), 以及猜中那一支该做什么(记下“赢了”并跳出)。下面的完整代码给出一种答案。

💡
为什么这次选 for 不选 while
猜测次数有上限(最多 7 次),这是“次数已知”的一面,用 for 顺手计数; 而“可能没到 7 次就猜中提前结束”,靠 break 解决。 两种工具各管一头,配合得正好。
实现

完整代码

guess_number.cpp CPP
#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    srand(time(0));
    int answer = rand() % 100 + 1;

    int maxTries = 7;          // 最多猜 7 次
    bool win = false;          // 是否猜中的标记

    std::cout << "我想好了一个 1~100 的数,你有 " << maxTries << " 次机会。" << std::endl;

    for (int i = 1; i <= maxTries; i++) {
        std::cout << "第 " << i << " 次猜,请输入:";
        int guess;
        std::cin >> guess;

        if (guess > answer) {
            std::cout << "大了" << std::endl;
        } else if (guess < answer) {
            std::cout << "小了" << std::endl;
        } else {
            std::cout << "恭喜!" << i << " 次就猜中了。" << std::endl;
            win = true;
            break;             // 猜中了,提前结束循环
        }
    }

    if (!win) {
        std::cout << "次数用完了,答案是 " << answer << "。" << std::endl;
    }

    return 0;
}
逐段看

for (int i = 1; i <= maxTries; i++)计数(第几次猜), 又限定上限(最多 7 次),i 还能直接拿来报告“几次猜中”。

win 这个标记是关键:循环可能因两种原因结束——猜中 break, 或次数耗尽自然退出。循环外靠 if (!win) 区分这两种结局,决定要不要公布答案。

测试

把每条岔路都走一遍

⚡ 动手实操 约 15 分钟

按清单逐项验证

跑起来,照下面的剧本各玩一局,确认行为符合预期:

场景期望表现
第一次就猜中提示“1 次就猜中”,立刻结束
故意每次猜太大每次都提示“大了”
故意每次猜太小每次都提示“小了”
7 次都没猜中公布答案,且答案确实是你没猜到的那个数
第 7 次刚好猜中祝贺“7 次猜中”,不再公布答案
💡
边界最容易错
“第 7 次刚好猜中”是最易出 bug 的一格:如果你的代码这时既祝贺又公布答案, 说明 win 标记或 break 漏了——回头检查猜中那一支。
拓展

让游戏更好玩

练习 10-1

范围越缩越小的提示

光提示“大了 / 小了”还能更贴心:维护一个当前可能区间 [low, high], 每次根据猜测结果收窄它,并提示玩家“答案在 lowhigh 之间”。

提示:初始 low = 1high = 100; 猜大了就把 high 改成 guess - 1,猜小了就把 low 改成 guess + 1

练习 10-2

玩完一局问“再来一局吗”

一局结束后问玩家是否再来(输入 y 继续、其它退出),用外层循环把整个游戏包起来, 每局重新生成答案。

💡
想一想
这层“要不要再玩”的循环,次数完全取决于玩家——该用 for 还是 while? 回到第 9 讲那条挑选标准。
练习 10-3

拒绝越界的猜测

如果玩家输入了 0200 这种不在 1~100 的数,提示“请猜 1~100 之间的数”, 并且这次不算进 7 次机会里

提示:把第 8 讲的输入校验思路搬过来——非法输入时用 continue 跳过本轮, 但别让它消耗掉一次计数。想想计数该怎么改才不会被 continue 误伤。

小结

模块三回顾

📖 理论讲解

第 8~10 讲,你掌握了

讲次核心内容
第 8 讲while、循环变量三动作、死循环
第 9 讲for、累加器、break / continue
第 10 讲随机数 + 循环 + 条件,做出完整小游戏

到这里,你的程序已经能判断、能重复,还能处理运行时才知道的输入—— 这正是大多数实用程序的骨架。

💡
下节课预告
猜数字游戏的代码已经开始变长了。如果游戏再复杂些,main 会越堆越乱。 下一模块学函数:把“生成答案”“判断一次猜测”这些步骤各自打包, 让代码像搭积木一样清清爽爽。