山林中有一座宁静的村庄,静得反常——食人魔就要来了!你需要在村庄四周布置哨塔和火焰陷阱。这些防御点不是随意摆放的,而是沿着边界、每隔固定距离放一个。如果用普通循环一个坐标一个坐标地写,代码会又长又乱。本单元你将学会 for 循环的第三个参数——步长(step),让循环变量不再只是"加一加一"地走,而是能大步流星地跳跃前进,甚至倒着走。
range(start, end, step) 的第三个参数 step 决定循环变量"每次跳多远"。正的 step 让它递增,负的 step 让它递减。配合 hero.moveXY(x, y) 沿边巡逻、hero.buildXY(type, x, y) 定点建造,你只用几行循环就能在村庄四条边上等距布满防御工事,把大量重复代码压缩成简洁的几行。
之前你写的 range(0, 5) 会依次产生 0、1、2、3、4——每次悄悄地加 1,这个"1"就是默认步长。但很多时候我们不想一格一格挪:布防的点每隔 20 个单位一个,倒计时每 10 秒报一次,跳格子每次跳 2 步……这时就要显式地把步长写出来。关卡概览一语道破:"for 循环不仅可以用于遍历数组,还可以一次增加 2、4、10 甚至 20 个单位!"
# 默认步长 1 for i in range(0, 5): print(i) # 0 1 2 3 4 # 步长 10,一次跳 10 for i in range(0, 100, 10): hero.say(i) # 0 10 20 ... 90
凡是"从某处开始、每隔固定距离做一次、到某处结束"的任务,步长循环都是最优解:沿墙每 20 米放一个哨塔、每 24 米埋一个陷阱、每 5 单位走一步。你只需告诉循环三件事——从哪开始、到哪结束、每次跨多大——剩下的重复动作它替你完成。
range(start, end, step) 有三个参数,位置和含义都固定:start 是起点(包含在内),end 是终点(不包含),step 是每次前进的量。循环变量从 start 出发,每轮加上 step,一旦越过 end 就停下。
这是最容易踩的坑。range 遵循"左闭右开":起点算数,终点不算。关卡北边界要从 x=40 走到 x=80(含 80),步长 20,如果写 range(40, 80, 20),产生的是 40、60——80 被漏掉了!所以必须把 end 写成比目标终点稍大的数,如 range(40, 81, 20),才能产生 40、60、80。默认代码的注释也特意提醒:"range 不包括第二个边界。"
| 写法 | 产生的序列 | 含 80 吗 |
|---|---|---|
| range(40, 80, 20) | 40, 60 | ❌ 漏了 |
| range(40, 81, 20) | 40, 60, 80 | ✅ 正确 |
当 step 为正数时,循环变量从 start 一路递增到接近 end。此时必须满足 start < end,否则循环一次都不执行。关卡里"沿北边界从 x=40 到 x=80"就是典型的正步长。
# 正步长:20, 40, 60, 80 for i in range(20, 100, 20): hero.say(i) # 20 40 60 80
当 step 为负数时,循环变量从 start 一路递减到接近 end。此时必须满足 start > end(起点比终点大)。关卡里"沿东边界从 y=40 到 y=20"就要用负步长:range(40, 19, -20) 产生 40、20——注意 end 写成 19(比 20 小 1),才能把 20 包含进来。
# 负步长:40, 20(end 写 19 才含 20) for y in range(40, 19, -20): hero.moveXY(80, y)
start < end,负步长要求 start > end。如果方向反了——比如 range(40, 20, 20)(起点大于终点却用正步长),或 range(20, 40, -20)(起点小于终点却用负步长)——range 会什么都不产生,循环体一次也不执行,防御点全没建成。
沿一条边巡逻的诀窍是:那条边上有一个坐标是固定的,另一个坐标随循环变量变化。走北边界(y=60 不变)时,让 x 随循环从 40 跳到 80;走东边界(x=80 不变)时,让 y 随循环从 40 降到 20。每到一个点就 hero.moveXY(x, y) 移动过去。
# 北边界:y 固定 60,x 从 40 递增到 80 for x in range(40, 81, 20): hero.moveXY(x, 60) hero.say("Here")
hero.buildXY(type, x, y) 让英雄直接在指定坐标建造指定类型的建筑,无需先移动过去。它比"先 moveXY 再建"更省时——在"危险的路线"里,你只有 80 秒,用 buildXY 能一口气把火焰陷阱布满四条通道。第一个参数是建筑类型字符串(如 "fire-trap"),后两个是坐标。
hero.moveXY(x, 60) # 英雄本体移动到该点
hero.buildXY("fire-trap", x, 114) # 直接在该点造陷阱
如果不用步长循环,你得手写每一个坐标:buildXY("fire-trap", 40, 114)、buildXY("fire-trap", 64, 114)、buildXY("fire-trap", 88, 114)……不仅冗长,改起来还容易出错。用一行 for x in range(40, 113, 24): 就能全部搞定。这正是编程里最重要的原则之一——DRY(Don't Repeat Yourself,不要重复自己)。
hero.buildXY("fire-trap",40,114) hero.buildXY("fire-trap",64,114) hero.buildXY("fire-trap",88,114) hero.buildXY("fire-trap",112,114)
for x in range(40, 113, 24): hero.buildXY("fire-trap", x, 114) # 一行循环 = 四行手写
buildNorthLine()、buildEastLine()、buildSouthLine()、buildWestLine() 四个函数,主程序只需依次调用它们。这是"步长循环"和第一单元"函数封装"的组合拳——循环消灭一条边内部的重复,函数消灭四条边之间的结构重复。
这一节聚焦每一关的策略、思路与算法设计,只展示用于说明的关键片段,完整通关程序请你自己动手完成。
宁静的村庄需要坚固的防御工事。每个农民都能造一座自动哨塔,塔会攻击城外一切单位。你要做的是沿着村庄的四条边界巡逻,每走到一个点就 hero.say("Here") 告诉农民在此建造,绕村一圈后躲回村里。
这是一个正方形边界,四条边各写一个 for 循环。关键是想清楚每条边"哪个坐标固定、哪个坐标变、往哪个方向走、用正还是负步长"。绕村一圈是顺时针:北边向右(x 增)、东边向下(y 减)、南边向左(x 减)、西边向上(y 增)。默认代码已经替你写好北、东两条边,留下南、西两条边让你补全。
四条边的方向和步长符号一一对应。北边界 y=60,x 从 40 递增到 80,用 range(40, 81, 20)(正步长)。东边界 x=80,y 从 40 递减到 20,用 range(40, 19, -20)(负步长,end 写 19 才含 20)。照此推理:南边界 y=20,x 从 60 递减到 20,用 range(60, 19, -20);西边界 x=20,y 从 40 递增到 60,用 range(40, 61, 20)。每个点都 hero.moveXY(...) 后 hero.say("Here")。
# 关键片段:需要你补全的南、西两条边 # 南边界 y=20,x 从 60 递减到 20(负步长) for x in range(60, 19, -20): hero.moveXY(x, 20) hero.say("Here") # 西边界 x=20,y 从 40 递增到 60(正步长) for y in range(40, 61, 20): hero.moveXY(20, y) hero.say("Here")
hero.moveXY(50, 40) 让英雄退到村庄中心的安全位置,否则英雄留在边界上可能被敌人攻击。
通往村庄的入口很多,你必须在四个方向的所有通道都埋下火焰陷阱。食人魔猎人队 80 秒后就到——时间紧迫,正是用 for 循环节省时间、让代码简洁的最佳场景。这一关引入了 buildXY,可以远程建造,比逐点移动快得多。
本关的结构比"边缘防御"更进一步:它把四条边分别封装成 buildNorthLine、buildEastLine、buildSouthLine、buildWestLine 四个函数,主程序末尾依次调用四个函数、最后 hero.moveXY(40, 94) 撤离。默认代码给好了北线函数作示范,其余三个函数体是 pass,等你填。策略就是:读懂每条边的注释(起止坐标 + 步长),把对应的 for 循环 + buildXY 填进各自的函数里。
每条边的参数都写在注释里,照着翻译即可。北线 y=114,x 从 40 到 112 步长 24:range(40, 113, 24)。东线 x=140,y 从 110 到 38 步长 18(递减):range(110, 37, -18)。南线 y=22,x 从 132 到 32 步长 20(递减):range(132, 31, -20)。西线 x=20,y 从 28 到 108 步长 16(递增):range(28, 109, 16)。递增用正步长、递减用负步长,end 记得比目标终点多走/少走一点以便包含终点。
# 关键片段:用函数封装每条边(示例两个) def buildEastLine(): # x=140 固定,y 从 110 递减到 38,步长 -18 for y in range(110, 37, -18): hero.buildXY("fire-trap", 140, y) def buildWestLine(): # x=20 固定,y 从 28 递增到 108,步长 16 for y in range(28, 109, 16): hero.buildXY("fire-trap", 20, y) # 定义后务必调用四个函数 buildNorthLine() buildEastLine() buildSouthLine() buildWestLine()
pass 换成循环只是"写好了函数体"。别忘了主程序末尾的 buildNorthLine()…buildWestLine() 四行调用——没有它们,函数里的代码一个陷阱都不会建。这一点和第一单元"定义后必须调用"是同一个道理。
buildXY 让英雄站在原地就能远程放置陷阱,四条边几十个点几乎瞬间布完——在限时关卡里,选对 API 就是选对了策略。
range(110, 37, -18) 实际产生 110、92、74、56、38——正好压线到 38。动手前不妨在纸上把序列展开算一遍,确认既没漏点、也没有点落到通道之外。
range(40, 80, 20),结果漏掉 80。正步长把 end 写成"终点 +1"。range(40, 20, -20),20 被排除。负步长把 end 写成"终点 −1"。start > end、负步长却 start < end,同样得到空循环。pass 换成循环后忘了在主程序调用该函数,陷阱不会建成。buildXY("类型", x, y),类型字符串在前,别和坐标顺序弄混。恭喜你守住了山林中的村庄!这一单元你解锁了 for 循环的第三个参数——步长,让循环从"逐一挪动"升级为"大步跳跃、还能倒着走"。你掌握了 range(start, end, step) 的三个参数含义、牢记了"左闭右开、end 取不到"的规则,学会了用正步长递增和负步长递减沿四个方向遍历坐标,用 moveXY 巡逻、用 buildXY 定点建造,并把"步长循环"和"函数封装"组合起来,用极简的代码消灭了大量重复。你在"边缘防御"里绕村布塔、在"危险的路线"里限时埋雷,两关都漂亮通过。来回顾一下核心概念:
| 核心概念 | 关键点 | 对应关卡 |
|---|---|---|
| range 三参数 | range(start, end, step) | 两关 |
| 左闭右开 | start 含、end 不含 | 两关 |
| 正步长递增 | step>0 且 start<end | 两关 |
| 负步长递减 | step<0 且 start>end | 两关 |
| end 补偿 | 含终点:+1 或 −1 | 两关 |
| moveXY 巡逻 | 固定一坐标、变另一坐标 | 边缘防御 |
| buildXY 建造 | buildXY("类型", x, y) | 危险的路线 |
| 循环消灭重复 | DRY,一行顶多行 | 两关 |
| 函数封装每条边 | 定义后必须调用 | 危险的路线 |
懂得用一个小小的步长参数掌控循环节奏、用循环与函数把重复代码化繁为简的英雄,
才是云峰之上真正高效的程序员。继续向雪山之巅挺进吧,勇敢的程序员!🏔️🛡️🔥
扣哒世界 编程知识 · 计算机科学 5(安息云峰):第九单元
扣哒世界教研团队