Spaces:
Running
#4 artofwar-decoy-sacrifice: no-cheat redesign — decoy-sacrifice enforced
Browse filesThe prior pack was cheatable (durable 2tnk brute-rush past a weak e1
picket won in ~4 turns; the decoy/credit-assignment capability was
never required). Redesigned end-to-end so the ONLY winning policy is
the decoy:
- enemy bot_type: guard (new engine leashed-defender behaviour): an
e3 (anti-tank) line spans the corridor at x=60, holds post, lunges
at a foe within aggro, snaps back past the leash.
- win = units_in_region_gte{(112,20) r6 n:3} (the THREE-tank main body
must reach the far objective) + reachable within_ticks; the unarmed
high-HP marker keeps the episode alive (no enemy-elim auto-terminal).
- A head-on push runs the full lethal e3 gauntlet → <3 arrive →
timeout LOSS. Do-nothing/preserve-everything → timeout LOSS. Only
baiting a segment off post with the fast jeeps opens a transient
gap for the tanks.
- Tiers: easy bare; medium tighter clock; hard seed-varied spawn
(anti-memorisation) + units_lost_lte:2 (only the 2 bait jeeps may
be spent). Off-map hard spawn (y40/48) also fixed.
VERIFIED no defect: scripted brute / stall / preserve LOSE on every
tier and seed (cheat closed); a correct scripted decoy WINS easy &
medium losing exactly the 2 bait jeeps (solvable, sacrifice
mandatory). qwen/qwen3.6-flash brute-rushes → LOSS all tiers = valid
capability discrimination. botgen: +guard. Suite 380 passed.
- docs/scenarios.html +0 -0
- openra_bench/botgen.py +6 -1
- openra_bench/scenarios/packs/artofwar-decoy-sacrifice.yaml +119 -156
- tests/test_artofwar.py +5 -3
- tests/test_botgen.py +1 -1
|
The diff for this file is too large to render.
See raw diff
|
|
|
|
@@ -17,13 +17,18 @@ Behaviours (all derive targets from live world state — no map coords):
|
|
| 17 |
rusher — relentless concentrated charge at the agent's mass; fast.
|
| 18 |
patrol — units oscillate around their own spawn; engage intruders.
|
| 19 |
turtle — hold the spawn position; return fire only.
|
|
|
|
|
|
|
|
|
|
| 20 |
"""
|
| 21 |
|
| 22 |
from __future__ import annotations
|
| 23 |
|
| 24 |
from typing import Any
|
| 25 |
|
| 26 |
-
BEHAVIORS: frozenset[str] = frozenset(
|
|
|
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
def read_enemy_bot(enemy: Any) -> str | None:
|
|
|
|
| 17 |
rusher — relentless concentrated charge at the agent's mass; fast.
|
| 18 |
patrol — units oscillate around their own spawn; engage intruders.
|
| 19 |
turtle — hold the spawn position; return fire only.
|
| 20 |
+
guard — leashed defender: holds its post; lunges at a
|
| 21 |
+
foe only within an aggro radius and snaps back
|
| 22 |
+
past a leash (a decoy can bait it off post).
|
| 23 |
"""
|
| 24 |
|
| 25 |
from __future__ import annotations
|
| 26 |
|
| 27 |
from typing import Any
|
| 28 |
|
| 29 |
+
BEHAVIORS: frozenset[str] = frozenset(
|
| 30 |
+
{"hunt", "rusher", "patrol", "turtle", "guard"}
|
| 31 |
+
)
|
| 32 |
|
| 33 |
|
| 34 |
def read_enemy_bot(enemy: Any) -> str | None:
|
|
@@ -1,188 +1,151 @@
|
|
| 1 |
meta:
|
| 2 |
id: artofwar-decoy-sacrifice
|
| 3 |
-
title: 'Decoy Sacrifice —
|
| 4 |
capability: reasoning
|
| 5 |
real_world_meaning: >
|
| 6 |
-
以利动之 — "move the enemy with the prospect of gain." A
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
robotics_analogue: >
|
| 14 |
-
Sacrificial-decoy planning
|
| 15 |
-
|
| 16 |
-
|
|
|
|
| 17 |
author: openra-bench
|
|
|
|
| 18 |
base_map: rush-hour-arena
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
base:
|
| 20 |
-
agent:
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
cash: 0
|
| 26 |
-
bot_type: ''
|
| 27 |
actors:
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
- type:
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
health: 100
|
| 47 |
-
facing: -1
|
| 48 |
-
count: 5
|
| 49 |
-
- type: fact # objective marker — episode can't end on guard-wipe
|
| 50 |
-
owner: enemy
|
| 51 |
-
position: [44, 24]
|
| 52 |
levels:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
easy:
|
| 54 |
description: >
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
win_condition:
|
| 58 |
all_of:
|
| 59 |
-
-
|
| 60 |
-
- within_ticks:
|
| 61 |
-
# Deadline reachable within max_turns (tick ≈ 93+90·(70-1) = 6303);
|
| 62 |
-
# after_ticks 6001 makes a staller LOSE instead of drawing. The
|
| 63 |
-
# intended bait-then-drive-through win lands far inside 6000.
|
| 64 |
fail_condition:
|
| 65 |
any_of:
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
max_turns:
|
|
|
|
|
|
|
|
|
|
| 69 |
medium:
|
| 70 |
-
description:
|
|
|
|
|
|
|
|
|
|
| 71 |
overrides:
|
| 72 |
actors:
|
| 73 |
-
- type: 2tnk
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
- type:
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
health: 100
|
| 85 |
-
facing: -1
|
| 86 |
-
count: 2
|
| 87 |
-
- type: e1
|
| 88 |
-
owner: enemy
|
| 89 |
-
position: [40, 24]
|
| 90 |
-
stance: 3
|
| 91 |
-
health: 100
|
| 92 |
-
facing: -1
|
| 93 |
-
count: 7
|
| 94 |
-
- type: fact # objective marker (see easy)
|
| 95 |
-
owner: enemy
|
| 96 |
-
position: [44, 24]
|
| 97 |
win_condition:
|
| 98 |
all_of:
|
| 99 |
-
-
|
| 100 |
-
- within_ticks:
|
| 101 |
-
# Deadline reachable within max_turns (tick ≈ 93+90·(80-1) = 7203);
|
| 102 |
-
# after_ticks 7001 makes a staller LOSE instead of drawing. The
|
| 103 |
-
# head-on route is fatal here — the decoy maneuver wins well under
|
| 104 |
-
# 7000.
|
| 105 |
fail_condition:
|
| 106 |
any_of:
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
max_turns:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
hard:
|
| 111 |
description: >
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
overrides:
|
| 118 |
actors:
|
| 119 |
# spawn_point 0 — northern staging
|
| 120 |
-
- type: 2tnk
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
- type:
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
health: 100
|
| 135 |
-
facing: -1
|
| 136 |
-
count: 2
|
| 137 |
-
spawn_point: 0
|
| 138 |
-
# spawn_point 1 — southern staging (same formation, shifted)
|
| 139 |
-
# spawn_point 1 — northern staging. WAS y=40/48 which is
|
| 140 |
-
# OFF-MAP on rush-hour-arena (MapSize 128x40, playable y≈2..37):
|
| 141 |
-
# cell (6,40) indexed past the 128*40 grid and panicked the
|
| 142 |
-
# engine. Relocated in-bounds, kept distinct from spawn_point
|
| 143 |
-
# 0's mid/south staging so the ≥2-spawn contract still holds.
|
| 144 |
-
- type: 2tnk
|
| 145 |
-
owner: agent
|
| 146 |
-
position: [6, 8]
|
| 147 |
-
stance: 3
|
| 148 |
-
health: 100
|
| 149 |
-
facing: -1
|
| 150 |
-
count: 3
|
| 151 |
-
spawn_point: 1
|
| 152 |
-
randomize:
|
| 153 |
-
position: {base: [6, 8], offset: 3}
|
| 154 |
-
- type: jeep
|
| 155 |
-
owner: agent
|
| 156 |
-
position: [6, 14]
|
| 157 |
-
stance: 3
|
| 158 |
-
health: 100
|
| 159 |
-
facing: -1
|
| 160 |
-
count: 2
|
| 161 |
-
spawn_point: 1
|
| 162 |
-
- type: e1
|
| 163 |
-
owner: enemy
|
| 164 |
-
position: [40, 24]
|
| 165 |
-
stance: 3
|
| 166 |
-
health: 100
|
| 167 |
-
facing: -1
|
| 168 |
-
count: 8
|
| 169 |
-
- type: fact # objective marker (see easy)
|
| 170 |
-
owner: enemy
|
| 171 |
-
position: [44, 24]
|
| 172 |
win_condition:
|
| 173 |
all_of:
|
| 174 |
-
-
|
| 175 |
-
- within_ticks:
|
| 176 |
-
- units_lost_lte: 2
|
| 177 |
-
# Deadline reachable within max_turns (tick ≈ 93+90·(90-1) = 8103);
|
| 178 |
-
# after_ticks 8001 makes a staller LOSE. Exceeding the bait-only
|
| 179 |
-
# loss cap (units_lost > 2 ⇒ a tank was spent) also loses
|
| 180 |
-
# immediately rather than drawing — this is what makes the
|
| 181 |
-
# credit-assignment capability load-bearing: a brute-force push
|
| 182 |
-
# that arrives but burned the armour is a LOSS, not a draw.
|
| 183 |
fail_condition:
|
| 184 |
any_of:
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
max_turns:
|
|
|
|
| 1 |
meta:
|
| 2 |
id: artofwar-decoy-sacrifice
|
| 3 |
+
title: 'Decoy Sacrifice — Divert Hunting Defenders So the Main Body Reaches the Objective'
|
| 4 |
capability: reasoning
|
| 5 |
real_world_meaning: >
|
| 6 |
+
以利动之 — "move the enemy with the prospect of gain." A reactive
|
| 7 |
+
HUNTING force (it actively pursues the nearest of your units) sits
|
| 8 |
+
astride the only corridor to the objective. Push the durable main
|
| 9 |
+
body straight through and the hunters converge and destroy it
|
| 10 |
+
before three of them arrive. The winning policy commits the fast,
|
| 11 |
+
expendable bait on a divergent vector so the hunters lock onto and
|
| 12 |
+
chase IT — clearing the corridor for the main body. This is
|
| 13 |
+
long-horizon credit assignment: a decoy maneuver whose payoff is
|
| 14 |
+
delayed and whose cost (the bait drawing fire / dying) looks
|
| 15 |
+
locally negative; greedy "keep everyone safe, push head-on" and
|
| 16 |
+
"do nothing" both fail.
|
| 17 |
robotics_analogue: >
|
| 18 |
+
Sacrificial-decoy planning against a pursuing adversary: expend or
|
| 19 |
+
risk a cheap agent to draw a reactive interceptor off the protected
|
| 20 |
+
corridor, accepting negative short-term reward for the delayed
|
| 21 |
+
arrival of the main payload.
|
| 22 |
author: openra-bench
|
| 23 |
+
|
| 24 |
base_map: rush-hour-arena
|
| 25 |
+
|
| 26 |
+
# The enemy is a LEASHED GUARD line (engine scripted bot 'guard'):
|
| 27 |
+
# each e3 holds its post and auto-fires in range, lunges at a foe
|
| 28 |
+
# within an aggro radius, and SNAPS BACK past a leash. Drive the
|
| 29 |
+
# column straight through and the whole line engages it (anti-tank
|
| 30 |
+
# rockets) — it dies before three arrive. Send the fast jeeps in as a
|
| 31 |
+
# decoy against one segment: those guards lunge off post after the
|
| 32 |
+
# bait, opening a transient gap the main body sprints through before
|
| 33 |
+
# they snap back. Greedy head-on / do-nothing both fail.
|
| 34 |
base:
|
| 35 |
+
agent: {faction: allies, cash: 0}
|
| 36 |
+
enemy: {faction: soviet, cash: 0, bot_type: guard}
|
| 37 |
+
tools: [move_units, attack_unit, stop]
|
| 38 |
+
planning: true
|
| 39 |
+
termination: {max_ticks: 12000}
|
|
|
|
|
|
|
| 40 |
actors:
|
| 41 |
+
# Main body — durable but slow; THREE must reach the far objective.
|
| 42 |
+
- {type: 2tnk, owner: agent, position: [6, 20], stance: 1, count: 3}
|
| 43 |
+
# Bait — fast (kites the foot hunters), expendable. The decoy.
|
| 44 |
+
- {type: jeep, owner: agent, position: [6, 24], stance: 1, count: 2}
|
| 45 |
+
# Hunting picket astride the direct line spawn(6,20)→objective.
|
| 46 |
+
# e3 = anti-tank rockets: lethal to an unsupported tank column.
|
| 47 |
+
- {type: e3, owner: enemy, position: [60, 6], stance: 2}
|
| 48 |
+
- {type: e3, owner: enemy, position: [60, 11], stance: 2}
|
| 49 |
+
- {type: e3, owner: enemy, position: [60, 16], stance: 2}
|
| 50 |
+
- {type: e3, owner: enemy, position: [60, 21], stance: 2}
|
| 51 |
+
- {type: e3, owner: enemy, position: [60, 26], stance: 2}
|
| 52 |
+
- {type: e3, owner: enemy, position: [60, 31], stance: 2}
|
| 53 |
+
- {type: e3, owner: enemy, position: [60, 36], stance: 2}
|
| 54 |
+
- {type: e1, owner: enemy, position: [60, 20], stance: 2, count: 4}
|
| 55 |
+
# Objective marker (far east). Unarmed, high-HP: keeps the episode
|
| 56 |
+
# alive (no enemy-elimination auto-terminal) and is the landmark.
|
| 57 |
+
- {type: fact, owner: enemy, position: [112, 20]}
|
| 58 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
levels:
|
| 60 |
+
# ── EASY ── the bare decoy skill: a modest hunting picket. A naive
|
| 61 |
+
# head-on column loses too many tanks to land 3 at the objective;
|
| 62 |
+
# leading the hunters off with the jeeps clears the way. Generous
|
| 63 |
+
# clock.
|
| 64 |
easy:
|
| 65 |
description: >
|
| 66 |
+
A hunting picket (rocket infantry + riflemen) blocks the lane to
|
| 67 |
+
the objective and chases your nearest unit. Get THREE tanks to
|
| 68 |
+
the objective (far east). Driving the column straight in gets it
|
| 69 |
+
shot apart before three arrive; send the fast jeeps in as bait on
|
| 70 |
+
a separate vector to pull the hunters off, then run the tanks
|
| 71 |
+
through. Idling or never committing loses on the clock.
|
| 72 |
+
overrides: {}
|
| 73 |
win_condition:
|
| 74 |
all_of:
|
| 75 |
+
- {units_in_region_gte: {x: 112, y: 20, radius: 6, n: 3}}
|
| 76 |
+
- {within_ticks: 5800}
|
|
|
|
|
|
|
|
|
|
| 77 |
fail_condition:
|
| 78 |
any_of:
|
| 79 |
+
- {after_ticks: 5801}
|
| 80 |
+
- {not: {own_units_gte: 1}}
|
| 81 |
+
max_turns: 66
|
| 82 |
+
|
| 83 |
+
# ── MEDIUM ── +1 controlled variable: a heavier anti-armor picket
|
| 84 |
+
# (more e3) so a head-on push is decisively fatal; tighter clock.
|
| 85 |
medium:
|
| 86 |
+
description: >
|
| 87 |
+
Heavier rocket-infantry picket — a head-on push is now decisively
|
| 88 |
+
fatal. Same task: divert the hunters with the bait, land THREE
|
| 89 |
+
tanks on the objective before the (tighter) deadline.
|
| 90 |
overrides:
|
| 91 |
actors:
|
| 92 |
+
- {type: 2tnk, owner: agent, position: [6, 20], stance: 1, count: 3}
|
| 93 |
+
- {type: jeep, owner: agent, position: [6, 24], stance: 1, count: 2}
|
| 94 |
+
- {type: e3, owner: enemy, position: [60, 6], stance: 2}
|
| 95 |
+
- {type: e3, owner: enemy, position: [60, 11], stance: 2}
|
| 96 |
+
- {type: e3, owner: enemy, position: [60, 16], stance: 2}
|
| 97 |
+
- {type: e3, owner: enemy, position: [60, 21], stance: 2}
|
| 98 |
+
- {type: e3, owner: enemy, position: [60, 26], stance: 2}
|
| 99 |
+
- {type: e3, owner: enemy, position: [60, 31], stance: 2}
|
| 100 |
+
- {type: e3, owner: enemy, position: [60, 36], stance: 2}
|
| 101 |
+
- {type: e1, owner: enemy, position: [60, 20], stance: 2, count: 5}
|
| 102 |
+
- {type: fact, owner: enemy, position: [112, 20]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
win_condition:
|
| 104 |
all_of:
|
| 105 |
+
- {units_in_region_gte: {x: 112, y: 20, radius: 6, n: 3}}
|
| 106 |
+
- {within_ticks: 6600}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
fail_condition:
|
| 108 |
any_of:
|
| 109 |
+
- {after_ticks: 6601}
|
| 110 |
+
- {not: {own_units_gte: 1}}
|
| 111 |
+
max_turns: 76
|
| 112 |
+
|
| 113 |
+
# ── HARD ── +1 controlled variable: seed-chosen staging latitude
|
| 114 |
+
# (two spawn_point groups, in-bounds) so the working decoy line can't
|
| 115 |
+
# be memorised; strongest picket; strict attrition cap on top (the
|
| 116 |
+
# main body must arrive nearly whole — only the bait may be spent).
|
| 117 |
hard:
|
| 118 |
description: >
|
| 119 |
+
Strongest hunting picket; the force stages from a seed-chosen
|
| 120 |
+
latitude (the decoy line that works varies by seed, so it can't
|
| 121 |
+
be memorised). Land THREE tanks on the objective AND lose ≤2
|
| 122 |
+
units (only the two bait jeeps may be spent — burning armour
|
| 123 |
+
fails) before the tight deadline.
|
| 124 |
overrides:
|
| 125 |
actors:
|
| 126 |
# spawn_point 0 — northern staging
|
| 127 |
+
- {type: 2tnk, owner: agent, position: [6, 10], stance: 1, count: 3, spawn_point: 0}
|
| 128 |
+
- {type: jeep, owner: agent, position: [6, 14], stance: 1, count: 2, spawn_point: 0}
|
| 129 |
+
# spawn_point 1 — southern staging (same formation, in-bounds)
|
| 130 |
+
- {type: 2tnk, owner: agent, position: [6, 30], stance: 1, count: 3, spawn_point: 1}
|
| 131 |
+
- {type: jeep, owner: agent, position: [6, 34], stance: 1, count: 2, spawn_point: 1}
|
| 132 |
+
- {type: e3, owner: enemy, position: [60, 6], stance: 2}
|
| 133 |
+
- {type: e3, owner: enemy, position: [60, 11], stance: 2}
|
| 134 |
+
- {type: e3, owner: enemy, position: [60, 16], stance: 2}
|
| 135 |
+
- {type: e3, owner: enemy, position: [60, 21], stance: 2}
|
| 136 |
+
- {type: e3, owner: enemy, position: [60, 26], stance: 2}
|
| 137 |
+
- {type: e3, owner: enemy, position: [60, 31], stance: 2}
|
| 138 |
+
- {type: e3, owner: enemy, position: [60, 36], stance: 2}
|
| 139 |
+
- {type: e1, owner: enemy, position: [60, 20], stance: 2, count: 6}
|
| 140 |
+
- {type: fact, owner: enemy, position: [112, 20]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
win_condition:
|
| 142 |
all_of:
|
| 143 |
+
- {units_in_region_gte: {x: 112, y: 20, radius: 6, n: 3}}
|
| 144 |
+
- {within_ticks: 7400}
|
| 145 |
+
- {units_lost_lte: 2}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
fail_condition:
|
| 147 |
any_of:
|
| 148 |
+
- {after_ticks: 7401}
|
| 149 |
+
- {not: {units_lost_lte: 2}}
|
| 150 |
+
- {not: {own_units_gte: 1}}
|
| 151 |
+
max_turns: 84
|
|
@@ -62,9 +62,11 @@ def test_indirect_hard_requires_zero_loss_traversal():
|
|
| 62 |
def test_decoy_hard_loss_cap_allows_bait_not_army():
|
| 63 |
c = compile_level(load_pack(PACKS / "artofwar-decoy-sacrifice.yaml"),
|
| 64 |
"hard")
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
| 68 |
|
| 69 |
|
| 70 |
@pytest.mark.parametrize("pid", FAMILY)
|
|
|
|
| 62 |
def test_decoy_hard_loss_cap_allows_bait_not_army():
|
| 63 |
c = compile_level(load_pack(PACKS / "artofwar-decoy-sacrifice.yaml"),
|
| 64 |
"hard")
|
| 65 |
+
# Redesigned: far-east objective (112,20); hard caps losses at 2
|
| 66 |
+
# (only the two bait jeeps may be spent — burning a tank fails).
|
| 67 |
+
at_obj = [(112, 20)] * 3
|
| 68 |
+
assert evaluate(c.win_condition, _ctx(at_obj, 5000, lost=2)) is True
|
| 69 |
+
assert evaluate(c.win_condition, _ctx(at_obj, 5000, lost=3)) is False
|
| 70 |
|
| 71 |
|
| 72 |
@pytest.mark.parametrize("pid", FAMILY)
|
|
@@ -15,7 +15,7 @@ from openra_bench.scenarios.schema import ScenarioPack
|
|
| 15 |
|
| 16 |
|
| 17 |
def test_behaviour_catalogue():
|
| 18 |
-
assert BEHAVIORS == {"hunt", "rusher", "patrol", "turtle"}
|
| 19 |
|
| 20 |
|
| 21 |
def test_read_enemy_bot_field_and_alias():
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
def test_behaviour_catalogue():
|
| 18 |
+
assert BEHAVIORS == {"hunt", "rusher", "patrol", "turtle", "guard"}
|
| 19 |
|
| 20 |
|
| 21 |
def test_read_enemy_bot_field_and_alias():
|