《编程农场》教程 (10):向日葵核电站!解锁模块化编程 (import) 与最值算法

欢迎回来,农场首席架构师!

在征服了傲娇的树木和极度需要照顾的巨型南瓜后,你的农场逻辑已经非常精密了。但是,你有没有发现无人机飞来飞去的速度有点慢? 今天,我们将解锁农场的“终极能源”——向日葵(Sunflower)!只要拥有了能量,你的无人机和代码执行速度会直接翻倍(2倍速)

同时,为了应对越来越复杂的农场系统,我们将引入 Python 编程中真正的大师级技巧——多文件管理与模块导入(import

1. 向日葵的“抢花瓣”游戏规则

向日葵的种植方法和胡萝卜完全一样,但它的收割规则非常特殊,就像一场选美比赛:

  1. 能量加成:收割向日葵不给果实,只给“能量”。

  2. 参赛门槛:农场上必须至少种有 10 株向日葵

  3. 寻找花魁(8倍奖励):每株向日葵有 7 到 15 片花瓣不等。如果你在这 10+ 株向日葵中,精准收割了花瓣数量最多的那一株,你将获得 8 倍 的巨额能量!

  4. 雷达探测:使用新函数 measure() 可以测出脚下向日葵的花瓣数。最棒的是,向日葵还没完全长大时,就能提前测出花瓣数了

如果瞎割一气,你只能拿保底能量;如果精准制导,你的农场将化身核电站!

2. 告别单一文件:模块导入(import)的魔法

在找“花魁”之前,我们必须先解决一个严峻的问题:随着代码越来越多(比如我们之前写的 try_harvestsmart_plant、加上移动找坐标的 goto(x,y)),全塞在一个文件里会让人崩溃。

在真正的软件开发中,我们会把代码分门别类地拆到不同的文件里。这就需要用到 import

方案 A:标准导入(官方推荐 👍)

假设你建了一个名叫 farm_utils.py 的文件,里面装满了你写好的移动和浇水函数。 在你的主文件里,你只需要一句话就能借用它们:

import farm_utils

# 使用时,必须带上前缀,指明是借谁的工具:
farm_utils.goto(3, 4) 

方案 B:解包导入(新手慎用 ⚠️)

官方说明书特意警告了这种写法:from farm_utils import (把里面所有的东西直接倒进现在的房间里)。 这种写法虽然调用时不用加前缀,但极其容易引发*“命名冲突”“导入循环锁死”**。所以,听官方的劝:老老实实使用 import file 语法!

3. 终极护盾:if __name__ == "__main__":

关于 import,有一个非常可怕的“副作用”:当你导入一个文件时,电脑会把你导入的那个文件从头到尾执行一遍! 假设你的 farm_utils.py 底部有一句测试用的 harvest(),当你在主文件里 import farm_utils 时,无人机会莫名其妙地原地挥一刀!

为了防止这种“副作用”,我们需要给文件加上一把安全锁

# 你的工具和函数定义在上面
def goto(x, y):
    pass

# 【安全锁】:只有当你直接点击运行这个文件时,锁里的代码才会执行。
# 如果别人只是 import 借用你的工具,锁里的代码绝对不会被触发!
if __name__ == "__main__":
    # 测试代码放这里
    goto(0,0)
    harvest()

4. 实战:搭建你的“向日葵核电站”

5.命名为 utils (你的工具箱)

在这个文件里,我们只放通用的移动功能:

# 文件名:utils

def goto(x, y):
    while get_pos_x() < x:
        move(East)
    while get_pos_x() > x:
        move(West)
    while get_pos_y() < y:
        move(North)
    while get_pos_y() > y:
        move(South)

# 工具箱不需要执行任何具体动作,所以不用写 if __name__ 锁。

同时我们把“判断是不是耕地”这个极其常用的动作,封装到工具箱里。

# ==========================================
# 文件名:utils
# ==========================================

def goto(x, y):
    while get_pos_x() < x:
        move(East)
    while get_pos_x() > x:
        move(West)
    while get_pos_y() < y:
        move(North)
    while get_pos_y() > y:
        move(South)

# 新增:智能耕地功能
def prepare_soil():
    # 如果脚下是草地,就翻成耕地
    if get_ground_type() == Grounds.Grassland:
        till()

6.编写主程序(降序扫描法)

现在,我们要写主程序了。你的思路极其完美,但有一个游戏机制的小细节我们需要兼顾: “农场上必须至少有 10 株向日葵,才能触发 8 倍能量。” 为了保证场上向日葵数量永远达标,我们在割掉一株最高花瓣的向日葵后,最好立刻在原地补种一株新的,这样全图的向日葵永远是满的!

来看这段极其干脆利落的代码:

# ==========================================
# 文件名:main
# ==========================================
import utils

def run_sunflower_reactor():
    size = get_world_size()
    
    # --- 第 1 步:全图遍历,种满向日葵 ---
    for x in range(size):
        for y in range(size):
            utils.goto(x, y)
            
            if get_entity_type() == None:
                utils.prepare_soil() # 调用工具箱里的耕地代码
                plant(Entities.Sunflower)
                
    # --- 第 2 步:降序收割(从 15 一路扫到 7) ---
    # range(15, 6, -1) 的意思是:从 15 开始,每次减 1,一直数到 7(不包含 6)
    for target_petals in range(15, 6, -1):
        
        # 拿着当前的目标花瓣数(比如 15),去全图巡视一遍
        for x in range(size):
            for y in range(size):
                utils.goto(x, y)
                
                # 确保脚下确实是向日葵,再去测花瓣
                if get_entity_type() == Entities.Sunflower:
                    
                    # 如果花瓣数刚好等于我们当前的目标!
                    if measure() == target_petals:
                        
                        # 等它彻底成熟
                        while not can_harvest():
                            pass 
                            
                        # 一刀收割!拿下当前的最高 8 倍加成!
                        harvest()
                        
                        # 【细节优化】:割完立刻补种,保证全图向日葵永远 > 10 株
                        utils.prepare_soil()
                        plant(Entities.Sunflower)

# 主程序入口锁
if __name__ == "__main__":
    while True:
        run_sunflower_reactor()

🧠 为什么这个逻辑“神乎其技”?

我发明的这个逻辑,完美利用了游戏底层的**“相对最大值”**规则! 游戏规定:如果你收获了花瓣数量最多的那一株,就能获得 8 倍能量。

  • 第 1 遍扫描(找 15 瓣):全场最大的肯定是 15,你把所有的 15 都割了,拿满了 8 倍能量。

  • 第 2 遍扫描(找 14 瓣):此时场上已经没有 15 了!所以现在的全场最大值变成了 14!你去割 14,依然能触发 8 倍能量加成!

  • 以此类推...:你一路扫到 7,你的每一刀,割的都是当时的“全场最大值”,你的每一刀都是 8 倍收益!

最后,找出代码中的错误!