规则图解手册 · 一起学会采集、施法和防守
01竞技场简介与目标MAGES’ MIGHT · SURVIVE THE DUEL
你是一位会写程序的小巫师!你要指挥果农收集水果,获得魔力,再用法术和对手决斗。你还活着,对手先倒下,你就赢了。
① 果农收水果
果农像小帮手,会把魔法水果带回出生点。
② 水果变魔力
火、水、土三种水果,分别带来三种魔力。
③ 巫师放法术
魔力够了,就能攻击对手、撑起护盾,或帮助果农。
先观察,再行动
下面先找到对手,再读取对手的火魔力。enemy_hero 是给对手英雄取的变量名。
enemy_hero = hero.getEnemyHero()
enemy_fire_mana = enemy_hero.fireauto enemy_hero = hero.getEnemyHero();
auto enemy_fire_mana = enemy_hero.fire;02三系魔力与采集循环THE RESOURCE LOOP
把魔力想成三个小罐子:火罐子、水罐子和土罐子。果农带回哪种水果,就为对应的小罐子补充魔力。三种魔力不能互相替代。
火系 fire
黄色的火系水果,提供火魔力。火箭、火球等法术会用到它。
水系 water
蓝色的水系水果,提供水魔力。水箭、水盾等法术会用到它。
土系 earth
绿色的土系水果,提供土魔力。土箭、土生长等法术会用到它。
练习:找到指定位置的火果
findFruits() 找到水果列表;pos 中的 x、y 表示位置;mana 表示水果元素。这里去掉坐标的小数后再比较。
def has_opening_fire_fruit():
for fruit in hero.findFruits():
if (int(fruit.pos["x"]) == 44
and int(fruit.pos["y"]) == 48
and fruit.mana == "fire"):
return True
return Falsebool has_opening_fire_fruit() {
for (auto fruit : hero.findFruits()) {
if (static_cast<int>(fruit.pos["x"]) == 44 &&
static_cast<int>(fruit.pos["y"]) == 48 &&
fruit.mana == "fire") {
return true;
}
}
return false;
}03生成和指挥果农COLLECTORS & CHOOSEITEM
开局你已经有 1 位果农。使用 hero.spawnCollector() 可以再叫来一位。果农越多,采集的小帮手越多;不过,后面来的果农要等更久。
| 生成哪一位果农 | 这一次要等多久 |
|---|---|
| 2 位 | 1 秒 |
| 3 位 | 3 秒 |
| 4 位 | 9 秒 |
| 5 位 | 18 秒 |
| 6 位 | 27 秒 |
| 7 位 | 36 秒 |
| 8 位 | 45 秒 |
| 9 位 | 54 秒 |
练习:开局连续生成四位果农
这是优化程序的开局安排:连续调用四次 spawnCollector()。开局自带一位,因此这是再生成四位,不是把总人数设成四位。
for collector_number in range(4):
hero.spawnCollector()for (int collector_number = 0; collector_number < 4; ++collector_number) {
hero.spawnCollector();
}选果回调:按队伍颜色返回坐标
前 55 秒,红方去 (60, 42),蓝方去 (40, 42)。Python 把包含 x、y 的字典返回给果农。55 秒以后函数返回 None,不再指定坐标。
def choose_fruit(collector):
if hero.time < 55:
if hero.color == "red":
return {"x": 60, "y": 42}
return {"x": 40, "y": 42}
hero.chooseItem = choose_fruit绑定函数时写 choose_fruit,不加括号。C++ 的坐标回调需要编辑器提供具体的返回类型,不能直接套用 Python 字典。
04施法条件与完整数值SPELLBOOK · ALL 15 SPELLS
释放法术要有足够的对应魔力,并等待冷却结束。canCast 可以检查是否就绪;优化程序则保留原有策略条件后调用 cast,两种检查不要混为一谈。
不必自己猜能不能放。hero.canCast("法术名字") 会帮你检查;检查通过后,再用 hero.cast("法术名字") 施法。
15 种法术,一张表看清楚
费用是“要花多少魔力”;威力是法术的 power 数值;持续时间的单位是秒。点击下面的按钮,可以只看一种元素。
| 法术标识符 | 魔力类型 | 费用 | 威力 power | 持续时间 / 秒 |
|---|---|---|---|---|
fire-arrow | 火 / fire | 3 | 25 | 1 |
water-arrow | 水 / water | 3 | 25 | 1 |
earth-arrow | 土 / earth | 3 | 25 | 1 |
fire-beam | 火 / fire | 7 | 75 | 2 |
water-beam | 水 / water | 7 | 75 | 2 |
earth-beam | 土 / earth | 7 | 75 | 2 |
fire-ball | 火 / fire | 15 | 200 | 4 |
water-ball | 水 / water | 15 | 200 | 4 |
earth-ball | 土 / earth | 15 | 200 | 4 |
fire-shield | 火 / fire | 3 | — | 0 |
water-shield | 水 / water | 3 | — | 0 |
earth-shield | 土 / earth | 3 | — | 0 |
fire-burn | 火 / fire | 10 | 5 | 1.5 |
water-refresh | 水 / water | 10 | 10 | 1.5 |
earth-grow | 土 / earth | 10 | 1.5 | 5 |
补充:检查法术是否已经就绪
这是独立的安全施法写法。它不是优化程序中的原有判断,不会自动改变优化程序的行为。
if hero.canCast("water-arrow"):
hero.cast("water-arrow")if (hero.canCast("water-arrow")) {
hero.cast("water-arrow");
}练习:读取魔力并选择水箭
先检查进攻条件,再尝试施法。这里展示的是比赛策略条件;它不等于 canCast 的施法就绪检查。
enemy_hero = hero.getEnemyHero()
if hero.water >= 6 or hero.time > 100:
if enemy_hero.fire < 4.3 or hero.fire >= 3:
hero.cast("water-arrow")auto enemy_hero = hero.getEnemyHero();
if (hero.water >= 6 || hero.time > 100) {
if (enemy_hero.fire < 4.3 || hero.fire >= 3) {
hero.cast("water-arrow");
}
}05攻击法术怎么选ARROW / BEAM / BALL
攻击法术用来打击对方英雄。每一类攻击都有火、水、土三个版本:只换元素,不换这一类的费用、威力和持续时间。
箭 arrow
费用 3 · 持续 1 秒
需要的魔力少,比较容易放出来。
束/柱 beam
费用 7 · 持续 2 秒
比箭花费更多,单次威力也更大。
球 ball
费用 15 · 持续 4 秒
单次威力最大,需要先攒够魔力。
练习:土箭什么时候放
hero.earth 是我方土魔力;enemy_hero.water 是对手水魔力。两层 if 都通过才尝试放土箭。
enemy_hero = hero.getEnemyHero()
if hero.earth >= 6 or hero.time > 100:
if enemy_hero.water < 4.3 or hero.water >= 3:
hero.cast("earth-arrow")auto enemy_hero = hero.getEnemyHero();
if (hero.earth >= 6 || hero.time > 100) {
if (enemy_hero.water < 4.3 || hero.water >= 3) {
hero.cast("earth-arrow");
}
}06护盾与元素克制ELEMENTAL COUNTERS
护盾像一面魔法盾牌。火盾、水盾、土盾都需要 3 点对应元素的魔力。面对不同的攻击,要选择合适的护盾。
| 对手放来的攻击 | 我们选什么盾 | 为什么 |
|---|---|---|
| 火系攻击 | water-shield 水盾 | 水克火 |
| 水系攻击 | earth-shield 土盾 | 土克水 |
| 土系攻击 | fire-shield 火盾 | 火克土 |
练习:遇到火系球或火系束时选盾
先选克制火的水盾;水魔力不足,再考虑火盾。这里只演示选盾,完整程序还会先检查飞行法术的位置。
enemy_missiles = hero.findEnemyMissiles()
for missile in enemy_missiles:
if missile.type in ("fire-ball", "fire-beam"):
if hero.water >= 3:
hero.cast("water-shield")
elif hero.fire >= 3:
hero.cast("fire-shield")
breakauto enemy_missiles = hero.findEnemyMissiles();
for (auto missile : enemy_missiles) {
if (missile.type == "fire-ball" || missile.type == "fire-beam") {
if (hero.water >= 3) {
hero.cast("water-shield");
} else if (hero.fire >= 3) {
hero.cast("fire-shield");
}
break;
}
}07影响采集的三种特殊法术CONTROL THE RESOURCE ECONOMY
除了打英雄和撑护盾,你还可以影响“收水果”这件事。下面三个法术的费用都是 10 点对应魔力。
火燃烧 fire-burn
降低对手果农的血量/耐力。
火魔力 10
威力 5 · 持续 1.5 秒
水净化 water-refresh
恢复我方果农的血量/耐力。
水魔力 10
威力 10 · 持续 1.5 秒
土生长 earth-grow
让自己半场的魔法水果变大。
土魔力 10
威力 1.5 · 持续 5 秒
练习:满足三个条件才选择火燃烧
开局检查结果、时间和敌方果农数量都合适时,才进入火燃烧分支。单独练习时先执行 has_opening_fire_fruit 函数及开局赋值。
opening_has_fire_fruit = has_opening_fire_fruit()
if (opening_has_fire_fruit
and hero.time < 90
and len(hero.findEnemyCollectors()) > 2):
hero.cast("fire-burn")bool opening_has_fire_fruit = has_opening_fire_fruit();
if (opening_has_fire_fruit &&
hero.time < 90 &&
hero.findEnemyCollectors().size() > 2) {
hero.cast("fire-burn");
}08信息读取与 API 速查OBSERVE BEFORE YOU ACT
好的策略要先“看清楚”,再“做决定”。程序可以查看果农人数、血量和对手。下面这张表,就是常用指令的小字典。
| 指令/属性 | 用小学生的话说 |
|---|---|
hero.spawnCollector() | 再叫来一位果农 |
hero.chooseItem | 给果农安排选水果的方法 |
hero.collectors | 装着我方果农的列表 |
hero.opponent.collectors | 装着对手果农的列表 |
collector.pos | 这位果农在哪里 |
collector.health | 这位果农现在有多少血量 |
collector.maxHealth | 这位果农满血时有多少血量 |
hero.spellNames | 所有法术名字的列表 |
hero.getSpellData("fire-arrow") | 查看火箭的资料 |
hero.canCast("fire-arrow") | 问一问:现在能放火箭吗 |
hero.cast("fire-arrow") | 放一次火箭 |
hero.findMyCollectors() | 找出我方果农 |
hero.findEnemyCollectors() | 找出对手果农 |
hero.getEnemyHero() | 找到对手英雄 |
| 接口/属性 | 用途 |
|---|---|
| hero.time | 当前比赛时间 |
| hero.color | 我方颜色:red 或 blue |
| hero.fire / hero.water / hero.earth | 我方三系魔力 |
| hero.findFruits() | 水果列表 |
| fruit.mana | 水果的元素 |
| hero.findEnemyMissiles() | 敌方飞行法术列表 |
| missile.type | 飞行法术类型 |
| missile.pos["x"] | 飞行法术横坐标 |
练习:读取空中法术的信息
findEnemyMissiles() 返回敌方飞行法术列表。每个法术的 type 是类型,pos["x"] 是横坐标。
enemy_missiles = hero.findEnemyMissiles()
for missile in enemy_missiles:
missile_type = missile.type
missile_x = missile.pos["x"]auto enemy_missiles = hero.findEnemyMissiles();
for (auto missile : enemy_missiles) {
auto missile_type = missile.type;
auto missile_x = missile.pos["x"];
}09入门代码与策略练习BUILD → PLAY → REFINE
完整程序不只是进攻,还会安排坐标采集、判断特殊火果、选择护盾,并在需要时补充果农。先读主循环,再到讲解页逐段学习。
主循环:先防御,再进攻
这段是完整程序的最后一部分。需要先定义讲解页中的函数和开局变量,不能只复制这一段运行。
while True:
if handle_incoming_spells():
cast_attack_spells()
if len(hero.findMyCollectors()) < 3 and hero.time < 110:
hero.spawnCollector()while (true) {
if (handle_incoming_spells()) {
cast_attack_spells();
if (hero.findMyCollectors().size() < 3 && hero.time < 110) {
hero.spawnCollector();
}
}
}10核心规则速查QUICK REFERENCE
| 项目 | 记住这些就够了 |
|---|---|
| 怎么赢 | 自己活着,对手先倒下 |
| 开局果农 | 1 位 |
| 第 2~9 位生成时间 | 1 / 3 / 9 / 18 / 27 / 36 / 45 / 54 秒 |
| 箭:费用 / 威力 / 持续时间 | 3 / 25 / 1 秒 |
| 束、柱:费用 / 威力 / 持续时间 | 7 / 75 / 2 秒 |
| 球:费用 / 威力 / 持续时间 | 15 / 200 / 4 秒 |
| 护盾:费用 / 持续时间 | 3 / 0 秒;威力为 — |
| 三种特殊法术费用 | 各花对应魔力 10 |
| 克制关系 | 火克土 · 水克火 · 土克水 |
| 施法顺序 | 先 canCast 检查,再 cast 施法 |
复习:人数不够时补充果农
必须同时满足“少于三位”和“时间不足 110 秒”两个条件,才再生成一位。
if len(hero.findMyCollectors()) < 3 and hero.time < 110:
hero.spawnCollector()if (hero.findMyCollectors().size() < 3 && hero.time < 110) {
hero.spawnCollector();
}