学径XUEJING · 个人学习平台通知设置

课程库 AI 主线 Python 第一步 › 第 7

综合练习课 —— 猜数字游戏

普通课60 分钟

本课导读

变量、类型、输入输出、条件、循环——零件都齐了,今天组装第一台"整机"。你将像真正的程序员一样工作:从需求出发,拆解步骤,由简到繁分三版迭代出一个完整的猜数字游戏。学完这课,"我写过一个完整的程序"就是事实而不是愿望了。

需求和一个小转折

经典的猜数字游戏:一方想好 1~100 之间的数,另一方来猜,每猜一次得到"大了/小了"的反馈,直到猜中。

小转折:网页环境里 input() 交互体验有限(弹窗太累),所以我们反过来——你当出题人,让程序当猜数字的高手。这样一来程序完整可跑,你还会顺便见识一个漂亮的算法思想。(想玩"人来猜"的版本?课末有 Colab 版完整代码。)

程序员的第一步:拆解

别急着写代码。先把"让程序猜数"拆成可执行的步骤:

  1. 定一个秘密数字(你说了算)
  2. 程序给出一个猜测
  3. 判断:大了?小了?中了?
  4. 根据反馈调整下一次猜测
  5. 重复 2-4 直到猜中,统计用了几次

对照一下工具箱:步骤 3 是 if/elif/else,步骤 5 是 while——每个步骤都对应你已经会的东西。这就是拆解的意义:大问题拆到"每一小步都会做",程序就写完了一半。

V1:先让"判断"跑起来

万里长征第一步,先只做"猜一次 + 判断":

Python

V1 很简陋,但它能跑——这比"构思一个完美程序"重要一百倍。迭代开发的信条:先让最小的核心转起来,再一圈圈加功能。

V2:加上循环和"聪明的调整"

程序该怎么根据"大了/小了"调整猜测?最聪明的策略是每次猜可能范围的正中间

  • 反馈"小了" → 答案在猜测右边 → 把范围下限提到 guess + 1
  • 反馈"大了" → 答案在猜测左边 → 把范围上限压到 guess - 1
  • 每猜一次,范围砍掉一半

这个策略有个正式名字:二分法。写出来只需要 while + if:

Python

新符号 //整除(1 + 100) // 2 得 50(普通除法 / 会得 50.5,猜数字要整数)。

secret 换成 1、100、99 这些"刁钻"的数运行——不管你怎么藏,它都稳稳收敛。防死循环自查也过关:每圈范围都在缩小,guess 终会等于 secret

V3:加计数器 + 让电脑出题

最后两块拼图:统计猜了几次(累加器的老朋友——计数器);再让电脑自己随机出题,用上你的第一个标准库模块 random

Python

多运行几次——每次的秘密数字都不同,但次数从不超过 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 开始一个一个往上猜"(线性猜法),统计次数。跑几次对比二分法,感受一下"好算法"和"笨算法"的差距。

Python
✅ 参考答案
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}:猜中了!")

随堂测验

随堂测验0 / 4 题正确

1. (1 + 100) // 2 的结果是?

2. 二分法猜 1~100 的数最多只要 7 次,本质原因是?

3. import random 这行代码在做什么?

4. 人机对战版里的 while True: 加 break,为什么不算“死循环 bug”?

本课小结

  • 完整程序的工作流:需求 → 拆解成"每步都会做"→ V1 最小可跑 → 迭代加功能
  • 二分法:每次猜中间、砍掉一半,1~100 最多 7 次——你的第一个算法思想
  • 新工具:// 整除、import randomabs()while True + break 套路
  • 你已经写出了第一个完整程序——下一课是本单元的关卡测验,去领证吧

说明

建议把 V3 的代码亲手(不复制)在 Colab 里重敲一遍并跑通——还记得 U0.1-3 的黄金法则吗:能自己敲出来并解释每一行,才算真的会了。

划选正文任意文字可高亮、批注或加入复习卡

讨论

载入中…