同学们,上一节课我们了解了破解迷宫的终极策略——“右手定则”。今天,我们要把这套理论翻译成无人机能听懂的 Python 代码。
这段代码看似很长,但逻辑极其严密。我们要像拆解机械表一样,把它分成三个部分来看。
🏗️ 第一阶段:召唤迷宫(准备工作)
要想走迷宫,我们得先有一个迷宫。在农场里,用“奇异物质”浇灌“灌木”,就能长出迷宫。
def solve_maze():
# 1. 探测环境:我们在迷宫里吗?
if get_entity_type() != Entities.Treasure and get_entity_type() != Entities.Hedge:
解释:无人机低头看一眼,如果脚下既不是“宝藏(Treasure)”也不是“树篱(Hedge,也就是迷宫的墙)”,说明我们在一片空地上。那我们就得先从零开始种一个迷宫。
# 2. 种下基础植物:灌木
if get_ground_type() == Grounds.Grassland:
till() # 把草地翻成泥土
plant(Entities.Bush) # 种下灌木
解释:这是我们的老套路了,确保有泥土,然后种下灌木。
# 3. 计算魔法材料的用量
mazes_unlocked = num_unlocked(Unlocks.Mazes)
substance_needed = get_world_size() * (2 ** (mazes_unlocked - 1))
解释:这是游戏官方给我们的计算公式。
num_unlocked:查一下我们把“迷宫科技”升级了多少次。**:在 Python 里,两个星号代表乘方。2 ** 3就是 $2^3$(2的3次方)。随着科技升级,需要的材料呈指数级增长。
# 4. 检查库存并召唤
if num_items(Items.Weird_Substance) >= substance_needed:
use_item(Items.Weird_Substance, substance_needed)
else:
return
解释:做事要谨慎。召唤前先看看背包里的奇异物质够不够。
够(
>=):使用物品,灌木瞬间变迷宫!不够(
else):执行return。重点记住return,它的意思是“罢工,直接退出整个函数”。如果材料不够还硬等,无人机会卡死,所以我们直接让它退出。
🧭 第二阶段:右手法则寻路(核心大脑)
迷宫生成了,无人机现在站在迷宫的入口。真正的考验开始了!
# 1. 打造我们的“指南针”
dirs = [North, East, South, West]
current_dir_idx = 0
解释:我们建了一个列表
dirs(Directions的缩写),把四个绝对方向按顺时针排好:北(0)、东(1)、南(2)、西(3)。current_dir_idx = 0:我们假定无人机一开始是面朝北方(第 0 个方向)的。
# 2. 不拿宝藏誓不罢休!
while get_entity_type() != Entities.Treasure:
解释:只要脚下踩的不是宝藏,这个循环就会一直转下去。
# 3. 相对方向的“数学魔法”
right_idx = (current_dir_idx + 1) % 4
left_idx = (current_dir_idx - 1) % 4
back_idx = (current_dir_idx + 2) % 4
解释:这是全篇最聪明的数学技巧!既然列表是顺时针排的,那么:
右边就是当前索引
+ 1。比如面朝北(0),右边就是东(1)。左边就是当前索引
- 1。后边就是当前索引
+ 2。为什么要用
% 4(取余数)? 假设无人机面朝西(3),它的右边应该是北(0)。但是 $3 + 1 = 4$,列表里根本没有第 4 个东西(会报错)!用% 4就能让数字像时钟一样绕回 0。这就是循环索引的魔法!
🚦 关键:会说话的 move() 指令
# 优先级 1:右边有路吗?
if move(dirs[right_idx]):
current_dir_idx = right_idx
超级重点:在编程农场里,
move()不仅是一个动作,它还会汇报结果!如果它成功走了一步,它会变成
True。如果它撞墙了没动,它会变成
False。
if move(...):这句话相当于无人机闭着眼睛往右撞一下。如果撞通了(返回True),条件成立,然后执行current_dir_idx = right_idx(告诉自己:我现在面向右边了)。
# 优先级 2:右边撞墙了,那前面有路吗?
elif move(dirs[current_dir_idx]):
pass
解释:如果上面那个
if撞墙了,就会来到elif(否则如果)。无人机尝试往“正前方”撞一下。如果走通了,因为方向没变,我们用pass(什么都不做,直接过)。
# 优先级 3:右边和前面都是墙,左边有路吗?
elif move(dirs[left_idx]):
current_dir_idx = left_idx
解释:继续尝试左边。如果通了,更新自己的朝向为左边。
# 优先级 4:三面都是墙(死胡同),掉头!
else:
move(dirs[back_idx])
current_dir_idx = back_idx
解释:如果前面的
if和elif全都撞墙了(返回 False),说明进了死胡同,就会执行else。无人机往后退一步,并把自己的朝向更新为“后面”。
💰 第三阶段:拿到宝藏!
# 离开 while 循环,说明我们踩到宝藏了!
harvest()
解释:当
while循环结束时,意味着脚下踩着的终于不是树篱,而是宝藏了。毫不犹豫地呼叫harvest(),把金币收入囊中!
def solve_maze():
# ================= 1. 生成迷宫 =================
# 如果脚下既不是宝藏也不是树篱,说明我们要种个新迷宫
if get_entity_type() != Entities.Treasure and get_entity_type() != Entities.Hedge:
# 确保脚下是耕地或草地可以种灌木
if get_ground_type() == Grounds.Grassland:
till()
plant(Entities.Bush)
# 计算需要的奇异物质数量 (按照游戏给的公式)
mazes_unlocked = num_unlocked(Unlocks.Mazes)
substance_needed = get_world_size() * (2 ** (mazes_unlocked - 1))
# 生成迷宫!
if num_items(Items.Weird_Substance) >= substance_needed:
use_item(Items.Weird_Substance, substance_needed)
else:
return # 物质不够,直接退出防止卡死
# ================= 2. 右手法则寻路 =================
# 定义方向列表,按照顺时针排列 (右转就是 index+1,左转是 index-1)
dirs = [North, East, South, West]
current_dir_idx = 0 # 初始面向 North
# 只要脚下不是宝藏,就一直找
while get_entity_type() != Entities.Treasure:
# 计算各个方向在列表中的索引 (% 4 确保索引在 0-3 之间循环)
right_idx = (current_dir_idx + 1) % 4
left_idx = (current_dir_idx - 1) % 4
back_idx = (current_dir_idx + 2) % 4
# 优先级 1:尝试向右走
if move(dirs[right_idx]):
current_dir_idx = right_idx # 成功向右,更新当前朝向
# 优先级 2:右边有墙,尝试直走
elif move(dirs[current_dir_idx]):
pass # 方向不变
# 优先级 3:右边和前面都有墙,尝试向左走
elif move(dirs[left_idx]):
current_dir_idx = left_idx
# 优先级 4:进了死胡同,掉头向后走
else:
move(dirs[back_idx])
current_dir_idx = back_idx
# ================= 3. 拿到宝藏! =================
harvest()
# 开始寻宝
while True:
solve_maze()