课程库 › AI 主线 › Python 第一步 › 第 7 课
综合练习课 —— 猜数字游戏
普通课约 60 分钟
本课导读
变量、类型、输入输出、条件、循环——零件都齐了,今天组装第一台"整机"。你将像真正的程序员一样工作:从需求出发,拆解步骤,由简到繁分三版迭代出一个完整的猜数字游戏。学完这课,"我写过一个完整的程序"就是事实而不是愿望了。
需求和一个小转折
经典的猜数字游戏:一方想好 1~100 之间的数,另一方来猜,每猜一次得到"大了/小了"的反馈,直到猜中。
小转折:网页环境里 input() 交互体验有限(弹窗太累),所以我们反过来——你当出题人,让程序当猜数字的高手。这样一来程序完整可跑,你还会顺便见识一个漂亮的算法思想。(想玩"人来猜"的版本?课末有 Colab 版完整代码。)
程序员的第一步:拆解
别急着写代码。先把"让程序猜数"拆成可执行的步骤:
- 定一个秘密数字(你说了算)
- 程序给出一个猜测
- 判断:大了?小了?中了?
- 根据反馈调整下一次猜测
- 重复 2-4 直到猜中,统计用了几次
对照一下工具箱:步骤 3 是 if/elif/else,步骤 5 是 while——每个步骤都对应你已经会的东西。这就是拆解的意义:大问题拆到"每一小步都会做",程序就写完了一半。
V1:先让"判断"跑起来
万里长征第一步,先只做"猜一次 + 判断":
V1 很简陋,但它能跑——这比"构思一个完美程序"重要一百倍。迭代开发的信条:先让最小的核心转起来,再一圈圈加功能。
V2:加上循环和"聪明的调整"
程序该怎么根据"大了/小了"调整猜测?最聪明的策略是每次猜可能范围的正中间:
- 反馈"小了" → 答案在猜测右边 → 把范围下限提到
guess + 1 - 反馈"大了" → 答案在猜测左边 → 把范围上限压到
guess - 1 - 每猜一次,范围砍掉一半
这个策略有个正式名字:二分法。写出来只需要 while + if:
新符号 // 是整除:(1 + 100) // 2 得 50(普通除法 / 会得 50.5,猜数字要整数)。
把 secret 换成 1、100、99 这些"刁钻"的数运行——不管你怎么藏,它都稳稳收敛。防死循环自查也过关:每圈范围都在缩小,guess 终会等于 secret。
V3:加计数器 + 让电脑出题
最后两块拼图:统计猜了几次(累加器的老朋友——计数器);再让电脑自己随机出题,用上你的第一个标准库模块 random:
多运行几次——每次的秘密数字都不同,但次数从不超过 7 次。因为 100 砍一半是 50、25、13、7、4、2、1——七刀之内必见真章。上一课"对折上珠峰"的指数增长,反过来用就是二分法的"指数收缩"。这是你遇到的第一个正经算法思想,阶段 3 讲向量检索时它还会回来。
提示
import random 是在说"把 Python 自带的随机数工具箱搬进来"。Python 的标准库里有大量这样的工具箱(后面会陆续认识 math、os、json……),import 就是取用它们的钥匙。
完整带注释版 + Colab 人机对战版
📦 人机对战版(你来猜,程序出题)—— 复制到 Colab 里玩
import random
secret = random.randint(1, 100) # 电脑想好一个数
tries = 0
print("我想好了一个 1~100 的数,你来猜!")
while True: # 一直玩,直到 break
guess = int(input("你猜:")) # input 返回字符串,记得转 int
tries = tries + 1
if guess < secret:
print("小了,再来")
elif guess > secret:
print("大了,再来")
else:
print(f"猜中了!一共猜了 {tries} 次")
break # 猜中,离场
这里的 while True: 是故意的"永真循环"——靠 break 退出,是交互程序的常见写法(上一课说死循环是 bug,但"死循环 + break"是合法套路:出口在循环体里)。
✍️ 练习
练习 1:扩大战场
把 V3 的范围从 1100 改成 11000(两处要改),运行几次,观察最多猜几次。想一想为什么只多了三四次。
✅ 答案与解释
改 random.randint(1, 1000) 和 high = 1000。最多 10 次:1000 → 500 → 250 → 125 → 63 → 32 → 16 → 8 → 4 → 2 → 1。范围扩大 10 倍,次数只加 3——每砍一刀范围减半,这就是二分法的威力。
练习 2:反向改造——最笨的猜法
把 V3 改成"从 1 开始一个一个往上猜"(线性猜法),统计次数。跑几次对比二分法,感受一下"好算法"和"笨算法"的差距。
✅ 参考答案
import random
secret = random.randint(1, 100)
guess = 1
tries = 1
while guess != secret:
guess = guess + 1
tries = tries + 1
print(f"从 1 数到 {guess},共 {tries} 次才猜中")
线性猜法平均要 50 次、最坏 100 次;二分法最坏 7 次。同一个问题,思路不同,效率差一个量级——这是"算法"二字的全部含义。
练习 3:温度提示(挑战)
给 V2 加个"温度提示":猜测和答案相差 5 以内时,打印"很接近了!"。需要一个新工具:abs(x) 返回 x 的绝对值,如 abs(-3) 是 3。
💡 提示
在打印"大了/小了"之前判断:if abs(guess - secret) <= 5:。
✅ 参考答案
secret = 73
low = 1
high = 100
guess = (low + high) // 2
while guess != secret:
if abs(guess - secret) <= 5:
print(f"猜 {guess}:很接近了!")
if guess < secret:
low = guess + 1
else:
high = guess - 1
guess = (low + high) // 2
print(f"猜 {guess}:猜中了!")
随堂测验
1. (1 + 100) // 2 的结果是?
2. 二分法猜 1~100 的数最多只要 7 次,本质原因是?
3. import random 这行代码在做什么?
4. 人机对战版里的 while True: 加 break,为什么不算“死循环 bug”?
本课小结
- 完整程序的工作流:需求 → 拆解成"每步都会做"→ V1 最小可跑 → 迭代加功能
- 二分法:每次猜中间、砍掉一半,1~100 最多 7 次——你的第一个算法思想
- 新工具:
//整除、import random、abs()、while True + break套路 - 你已经写出了第一个完整程序——下一课是本单元的关卡测验,去领证吧
说明
建议把 V3 的代码亲手(不复制)在 Colab 里重敲一遍并跑通——还记得 U0.1-3 的黄金法则吗:能自己敲出来并解释每一行,才算真的会了。
划选正文任意文字可高亮、批注或加入复习卡
讨论
载入中…