在这一模块中,我们遇到了一种非常有“强迫症”的植物——仙人掌。如果只是随便种下并收割,收益平平;但如果我们能根据它们的大小,将它们像排队一样排列整齐,就能触发极其爽快的“连锁收集”,获得爆发式的收益!
一、 核心机制:收益的“平方级”跃升
为什么要费尽心思给仙人掌排序?因为这关乎着极其夸张的数学收益。
如果没有排序,收割 1 株仙人掌得到 1 个资源;收割 81 株就是 81 个资源。
但如果触发了“连锁收集”: 你获得的资源是仙人掌总数的平方。在 $9 \times 9$ 的农场里,一次性收割 81 株排好序的仙人掌,收益将是 $81 \times 81 = 6561$ 个!这就是算法带来的效率跃升。
📏 仙人掌的“强迫症”规则
大小测量: 仙人掌的大小是 0- 9的随机数。我们可以用
measure()获取脚下仙人掌的大小,或者用measure(direction)获取旁边地块仙人掌的大小。排序标准:
右边 (East) 和 上边 (North) 的仙人掌,必须 大于或等于 自己的大小。
左边 (West) 和 下边 (South) 的仙人掌,必须 小于或等于 自己的大小。
简单来说:越往右上角,仙人掌越大;越往左下角,仙人掌越小。
状态指示灯: 棕色代表未排序,绿色代表已排序。全屏变绿时,收割任意一株即可触发连锁。
二、 课堂代码精讲:二维空间的“冒泡排序”
我们在课堂上编写的 have_sorted() 函数,实际上是经典计算机算法“冒泡排序”在二维平面上的变体应用。我们来看看它是如何通过 swap(direction) 函数实现全图排序的:
1. 核心循环与“巡逻兵”
is_sorted = False
while not is_sorted:
is_sorted = True # 假设这一轮已经排好序了
for x in range(get_world_size()):
for y in range(get_world_size()):
tool.move_to(x, y)
current_size = measure()
状态标记 (
is_sorted): 这是冒泡排序的灵魂。程序在每一轮开始前,都乐观地假设“已经排好了”(设为True)。只要在这一轮巡视中发生过任何一次位置交换,就说明还没排好(立刻被无情地改为False),下一轮就得重新再检查一遍。直到某一轮巡视下来,一次交换都没发生,循环才会结束。
2. “冒泡”过程:把大个子往右上角推
# 1. 与右侧 (East) 比较
if x < get_world_size() - 1: # 确保右边还有地块(边界保护)
east_size = measure(East)
# 如果当前的比较大,就把当前的“大个子”推到右边去
if east_size != None and current_size > east_size:
swap(East)
is_sorted = False
边界保护:
if x < get_world_size() - 1这句非常关键,防止无人机在最右侧边缘时还要去测右边的格子,导致报错。位置互换 (
swap): 当无人机发现脚下的仙人掌比右边(或上边)的大时,直接使用swap()函数把它们对调。这样一轮轮比较下来,最大的仙人掌就像水底的气泡一样,一点点“冒”到了农场的最右上角。
3. 收获果实
while True:
plant_all_cactus() # 铺满仙人掌
have_sorted() # 启动冒泡排序,直到全图变绿
tool.move_to(0,0) # 移动到左下角(其实全绿后移动到哪里都可以)
harvest() # 触发平方级大丰收!
三、 算法思维总结
同学们,这段代码虽然看起来有些长,但它其实只做了一件事:制定一条简单的微观规则(只管自己和右边、上边的比较),通过计算机不知疲倦的循环执行,最终实现了宏观上的完美秩序(全图排序)。 这就是计算机编程解决问题的核心思维!
📝 课后思考题:
“冒泡排序”虽然写起来简单易懂,但它的效率并不是最高的。如果农场变大(比如变成 $15 \times 15$),无人机需要来回巡逻很多圈才能排好,非常浪费时间。你能查阅资料,了解一下其他更快的排序算法(比如“插入排序”或“快速排序”)的核心思想吗