cogames 0.3.64__py3-none-any.whl → 0.3.65__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. cogames/cli/mission.py +25 -35
  2. cogames/cli/submit.py +1 -1
  3. cogames/cogs_vs_clips/clips.py +86 -0
  4. cogames/cogs_vs_clips/cog.py +14 -7
  5. cogames/cogs_vs_clips/cogsguard_tutorial.py +10 -11
  6. cogames/cogs_vs_clips/config.py +38 -0
  7. cogames/cogs_vs_clips/{cogs_vs_clips_mapgen.md → docs/cogs_vs_clips_mapgen.md} +6 -7
  8. cogames/cogs_vs_clips/evals/README.md +4 -4
  9. cogames/cogs_vs_clips/evals/cogsguard_evals.py +21 -6
  10. cogames/cogs_vs_clips/evals/diagnostic_evals.py +13 -100
  11. cogames/cogs_vs_clips/evals/difficulty_variants.py +9 -18
  12. cogames/cogs_vs_clips/evals/integrated_evals.py +8 -60
  13. cogames/cogs_vs_clips/evals/spanning_evals.py +48 -54
  14. cogames/cogs_vs_clips/mission.py +65 -277
  15. cogames/cogs_vs_clips/missions.py +16 -26
  16. cogames/cogs_vs_clips/sites.py +35 -25
  17. cogames/cogs_vs_clips/stations.py +33 -82
  18. cogames/cogs_vs_clips/team.py +44 -0
  19. cogames/cogs_vs_clips/{procedural.py → terrain.py} +12 -6
  20. cogames/cogs_vs_clips/variants.py +41 -118
  21. cogames/core.py +87 -0
  22. cogames/verbose.py +2 -2
  23. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/METADATA +2 -2
  24. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/RECORD +28 -27
  25. cogames/cogs_vs_clips/cogsguard_reward_variants.py +0 -153
  26. cogames/cogs_vs_clips/mission_utils.py +0 -19
  27. cogames/cogs_vs_clips/tutorial_missions.py +0 -25
  28. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/WHEEL +0 -0
  29. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/entry_points.txt +0 -0
  30. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/licenses/LICENSE +0 -0
  31. {cogames-0.3.64.dist-info → cogames-0.3.65.dist-info}/top_level.txt +0 -0
@@ -1,54 +1,21 @@
1
1
  from __future__ import annotations
2
2
 
3
- from pathlib import Path
4
3
  from typing import Dict
5
4
 
6
5
  from pydantic import Field
7
6
 
8
7
  from cogames.cogs_vs_clips.cog import CogConfig
9
- from cogames.cogs_vs_clips.mission import Mission, Site
10
- from mettagrid.config.game_value import stat
8
+ from cogames.cogs_vs_clips.mission import CvCMission
9
+ from cogames.cogs_vs_clips.sites import EVALS, get_map
10
+ from cogames.core import CoGameSite
11
11
  from mettagrid.config.handler_config import Handler
12
12
  from mettagrid.config.mettagrid_config import (
13
- ChestConfig,
14
13
  MettaGridConfig,
15
- ResourceLimitsConfig,
16
14
  )
17
15
  from mettagrid.config.mutation.resource_mutation import updateActor
18
- from mettagrid.config.reward_config import reward
19
- from mettagrid.map_builder.map_builder import MapBuilderConfig
20
- from mettagrid.mapgen.mapgen import MapGen
21
16
 
22
17
  RESOURCE_NAMES: tuple[str, ...] = ("carbon", "oxygen", "germanium", "silicon")
23
18
 
24
- MAPS_DIR = Path(__file__).resolve().parent.parent.parent / "maps"
25
-
26
-
27
- def get_map(map_name: str) -> MapBuilderConfig:
28
- """Load a map builder configuration from the local diagnostics directory."""
29
- normalized = map_name
30
- if normalized.startswith("evals/"):
31
- normalized = f"diagnostic_evals/{normalized.split('/', 1)[1]}"
32
- map_path = MAPS_DIR / normalized
33
- if not map_path.exists():
34
- raise FileNotFoundError(f"Diagnostic map not found: {map_path}")
35
- # Wrap AsciiMapBuilderConfig in MapGen.Config to match standard get_map() behavior
36
- return MapGen.Config(
37
- instance=MapBuilderConfig.from_uri(str(map_path)),
38
- instances=1, # Force single instance - use spawn points from ASCII map directly
39
- fixed_spawn_order=False,
40
- instance_border_width=0, # Don't add border - maps already have borders built in
41
- )
42
-
43
-
44
- EVALS = Site(
45
- name="evals",
46
- description="Diagnostic evaluation arenas.",
47
- map_builder=get_map("evals/diagnostic_radial.map"),
48
- min_cogs=1,
49
- max_cogs=4,
50
- )
51
-
52
19
 
53
20
  # Generous cog config for diagnostic missions: high limits and full energy regen
54
21
  _GENEROUS_COG = CogConfig(
@@ -64,25 +31,11 @@ _GENEROUS_COG = CogConfig(
64
31
  influence_regen=0,
65
32
  )
66
33
 
67
- # Same but without generous energy regen (for charge-up diagnostics)
68
- _MODEST_COG = CogConfig(
69
- gear_limit=255,
70
- hp_limit=255,
71
- heart_limit=255,
72
- energy_limit=255,
73
- cargo_limit=255,
74
- initial_energy=255,
75
- initial_hp=100,
76
- energy_regen=1,
77
- hp_regen=0,
78
- influence_regen=0,
79
- )
80
-
81
34
 
82
- class _DiagnosticMissionBase(Mission):
35
+ class _DiagnosticMissionBase(CvCMission):
83
36
  """Base class for minimal diagnostic evaluation missions."""
84
37
 
85
- site: Site = EVALS
38
+ site: CoGameSite = EVALS
86
39
  cog: CogConfig = Field(default_factory=lambda: _GENEROUS_COG.model_copy())
87
40
 
88
41
  map_name: str = Field(default="evals/diagnostic_eval_template.map")
@@ -90,15 +43,9 @@ class _DiagnosticMissionBase(Mission):
90
43
  required_agents: int | None = Field(default=None)
91
44
 
92
45
  inventory_seed: Dict[str, int] = Field(default_factory=dict)
93
- communal_chest_hearts: int | None = Field(default=None)
94
- resource_chest_stock: Dict[str, int] = Field(default_factory=dict)
95
46
  # If True, give agents high energy capacity and regen (overridden by specific missions)
96
47
  generous_energy: bool = Field(default=True)
97
48
 
98
- # Disable clips events for diagnostic evals
99
- clips_scramble_start: int = Field(default=99999)
100
- clips_align_start: int = Field(default=99999)
101
-
102
49
  def configure_env(self, cfg: MettaGridConfig) -> None: # pragma: no cover - hook for subclasses
103
50
  """Hook for mission-specific environment alterations."""
104
51
 
@@ -114,10 +61,6 @@ class _DiagnosticMissionBase(Mission):
114
61
  cfg.game.map_builder = forced_map
115
62
  cfg.game.max_steps = self.max_steps
116
63
  self._apply_inventory_seed(cfg)
117
- self._apply_communal_chest(cfg)
118
- self._apply_resource_chests(cfg)
119
- # Finally, normalize rewards so a single deposited heart yields at most 1 reward.
120
- self._apply_heart_reward_cap(cfg)
121
64
  self.configure_env(cfg)
122
65
  return cfg
123
66
  finally:
@@ -134,45 +77,15 @@ class _DiagnosticMissionBase(Mission):
134
77
  seed = dict(cfg.game.agent.inventory.initial)
135
78
  seed.update(self.inventory_seed)
136
79
  cfg.game.agent.inventory.initial = seed
137
-
138
- def _apply_communal_chest(self, cfg: MettaGridConfig) -> None:
139
- if self.communal_chest_hearts is None:
140
- return
141
- chest = cfg.game.objects.get("communal_chest")
142
- if isinstance(chest, ChestConfig):
143
- chest.inventory.initial = {"heart": self.communal_chest_hearts}
144
-
145
- def _apply_resource_chests(self, cfg: MettaGridConfig) -> None:
146
- if not self.resource_chest_stock:
147
- return
148
- for resource, amount in self.resource_chest_stock.items():
149
- chest_cfg = cfg.game.objects.get(f"chest_{resource}")
150
- if isinstance(chest_cfg, ChestConfig):
151
- chest_cfg.inventory.initial = {resource: amount}
152
-
153
- def _apply_heart_reward_cap(self, cfg: MettaGridConfig) -> None:
154
- """Normalize diagnostics so a single deposited heart yields at most 1 reward per episode.
155
-
156
- - Make each agent-deposited heart worth exactly 1.0 reward (credited only to the depositor).
157
- - Ensure all chests can store at most 1 heart so total reward per episode cannot exceed 1.
158
- """
159
- agent_cfg = cfg.game.agent
160
- rewards = dict(agent_cfg.rewards)
161
- rewards["chest_heart_deposited_by_agent"] = reward(stat("chest.heart.deposited_by_agent"))
162
- agent_cfg.rewards = rewards
163
-
164
- # Cap heart capacity for every chest used in diagnostics (communal or resource-specific).
165
- for _name, obj in cfg.game.objects.items():
166
- if not isinstance(obj, ChestConfig):
167
- continue
168
- # Find existing heart limit or create new one
169
- heart_limit = obj.inventory.limits.get("heart", ResourceLimitsConfig(min=1, resources=["heart"]))
170
- heart_limit.min = 1
171
- obj.inventory.limits["heart"] = heart_limit
80
+ # Also apply to per-agent configs (used by CvCMission)
81
+ for agent_cfg in cfg.game.agents:
82
+ agent_seed = dict(agent_cfg.inventory.initial)
83
+ agent_seed.update(self.inventory_seed)
84
+ agent_cfg.inventory.initial = agent_seed
172
85
 
173
86
 
174
87
  # ----------------------------------------------------------------------
175
- # Diagnostics (non-hub)
88
+ # Diagnostic missions (no assemblers)
176
89
  # ----------------------------------------------------------------------
177
90
 
178
91
 
@@ -234,7 +147,7 @@ class DiagnosticChargeUp(_DiagnosticMissionBase):
234
147
  max_steps: int = Field(default=250)
235
148
 
236
149
  def configure_env(self, cfg: MettaGridConfig) -> None:
237
- # Set starting energy to 30 and no regen
150
+ # Set starting energy to 60 and no regen
238
151
  agent = cfg.game.agent
239
152
  agent.inventory.initial = dict(agent.inventory.initial)
240
153
  agent.inventory.initial["energy"] = 60
@@ -302,7 +215,7 @@ class DiagnosticChargeUpHard(_DiagnosticMissionBase):
302
215
  max_steps: int = Field(default=350)
303
216
 
304
217
  def configure_env(self, cfg: MettaGridConfig) -> None:
305
- # Set starting energy to 30 and no regen
218
+ # Set starting energy to 60 and no regen
306
219
  agent = cfg.game.agent
307
220
  agent.inventory.initial = dict(agent.inventory.initial)
308
221
  agent.inventory.initial["energy"] = 60
@@ -9,11 +9,14 @@ energy regen, move cost, and capacity limits.
9
9
  from __future__ import annotations
10
10
 
11
11
  import logging
12
- from typing import override
12
+ from typing import TYPE_CHECKING, override
13
13
 
14
14
  from pydantic import Field
15
15
 
16
- from cogames.cogs_vs_clips.mission import Mission, MissionVariant
16
+ from cogames.core import CoGameMissionVariant
17
+
18
+ if TYPE_CHECKING:
19
+ from cogames.cogs_vs_clips.mission import CvCMission
17
20
  from mettagrid.config.mettagrid_config import MettaGridConfig
18
21
 
19
22
  logger = logging.getLogger(__name__)
@@ -28,7 +31,7 @@ ENERGY_REGEN_FLOOR = 0
28
31
  # =============================================================================
29
32
 
30
33
 
31
- class DifficultyLevel(MissionVariant):
34
+ class DifficultyLevel(CoGameMissionVariant):
32
35
  """Configuration for a difficulty level."""
33
36
 
34
37
  name: str = Field(description="Difficulty name (easy, medium, hard, brutal, etc.)")
@@ -45,24 +48,12 @@ class DifficultyLevel(MissionVariant):
45
48
  max_steps_override: int | None = Field(default=None)
46
49
 
47
50
  @override
48
- def modify_mission(self, mission: Mission):
51
+ def modify_mission(self, mission: CvCMission):
49
52
  """Apply a difficulty level to a mission instance."""
50
- # Energy regen
51
- if self.energy_regen_override is not None:
52
- mission.cog.energy_regen = self.energy_regen_override
53
- else:
54
- mission.cog.energy_regen = max(0, int(mission.cog.energy_regen * self.energy_regen_mult))
55
-
56
- # Mission-level overrides
57
- if self.move_energy_cost_override is not None:
58
- mission.cog.move_energy_cost = self.move_energy_cost_override
59
- if self.energy_capacity_override is not None:
60
- mission.cog.energy_limit = self.energy_capacity_override
61
- if self.cargo_capacity_override is not None:
62
- mission.cog.cargo_limit = self.cargo_capacity_override
53
+ pass # No mission-level modifications needed currently
63
54
 
64
55
  @override
65
- def modify_env(self, mission: Mission, env: MettaGridConfig):
56
+ def modify_env(self, mission: CvCMission, env: MettaGridConfig):
66
57
  if self.max_steps_override is not None:
67
58
  env.game.max_steps = self.max_steps_override
68
59
 
@@ -2,22 +2,18 @@ from __future__ import annotations
2
2
 
3
3
  import logging
4
4
 
5
- from cogames.cogs_vs_clips.mission import Mission, Site
6
- from cogames.cogs_vs_clips.procedural import MachinaArena
5
+ from cogames.cogs_vs_clips.mission import CvCMission
7
6
  from cogames.cogs_vs_clips.sites import HELLO_WORLD
7
+ from cogames.cogs_vs_clips.terrain import MachinaArena
8
8
  from cogames.cogs_vs_clips.variants import (
9
9
  DarkSideVariant,
10
- DistantResourcesVariant,
11
- EmptyBaseVariant,
12
- PackRatVariant,
13
- QuadrantBuildingsVariant,
14
- SingleResourceUniformVariant,
15
10
  )
11
+ from cogames.core import CoGameSite
16
12
  from mettagrid.mapgen.mapgen import MapGen
17
13
 
18
14
  logger = logging.getLogger(__name__)
19
15
 
20
- SMALL_HELLO_WORLD = Site(
16
+ SMALL_HELLO_WORLD = CoGameSite(
21
17
  name="small_hello_world",
22
18
  description="Small hello world map.",
23
19
  map_builder=MapGen.Config(width=50, height=50, instance=MachinaArena.Config(spawn_count=20)),
@@ -25,7 +21,7 @@ SMALL_HELLO_WORLD = Site(
25
21
  max_cogs=20,
26
22
  )
27
23
 
28
- MEDIUM_HELLO_WORLD = Site(
24
+ MEDIUM_HELLO_WORLD = CoGameSite(
29
25
  name="medium_hello_world",
30
26
  description="Medium hello world map.",
31
27
  map_builder=MapGen.Config(width=100, height=100, instance=MachinaArena.Config(spawn_count=20)),
@@ -33,7 +29,7 @@ MEDIUM_HELLO_WORLD = Site(
33
29
  max_cogs=20,
34
30
  )
35
31
 
36
- LARGE_HELLO_WORLD = Site(
32
+ LARGE_HELLO_WORLD = CoGameSite(
37
33
  name="large_hello_world",
38
34
  description="Large hello world map.",
39
35
  map_builder=MapGen.Config(width=150, height=150, instance=MachinaArena.Config(spawn_count=20)),
@@ -41,65 +37,17 @@ LARGE_HELLO_WORLD = Site(
41
37
  max_cogs=20,
42
38
  )
43
39
 
44
- # Resource Bottleneck evals
45
- OxygenBottleneck = Mission(
46
- name="oxygen_bottleneck",
47
- description="Oxygen is the limiting resource; agents must prioritize oxygen over other resources.",
48
- site=HELLO_WORLD,
49
- variants=[
50
- EmptyBaseVariant(missing=["oxygen_extractor"]),
51
- SingleResourceUniformVariant(building_name="oxygen_extractor"),
52
- PackRatVariant(),
53
- ],
54
- )
55
-
56
40
  # Energy Starved evals
57
- EnergyStarved = Mission(
41
+ EnergyStarved = CvCMission(
58
42
  name="energy_starved",
59
43
  description="Energy is the limiting resource; agents must prioritize energy over other resources.",
60
44
  site=HELLO_WORLD,
61
45
  variants=[
62
- EmptyBaseVariant(),
63
46
  DarkSideVariant(),
64
47
  ],
65
48
  )
66
49
 
67
- # Collect Distant Resources evals
68
- DistantResources = Mission(
69
- name="distant_resources",
70
- description="Resources scattered far from base; heavy routing coordination.",
71
- site=HELLO_WORLD,
72
- variants=[
73
- EmptyBaseVariant(),
74
- DistantResourcesVariant(),
75
- ],
76
- )
77
-
78
- # Divide and Conquer evals
79
- QuadrantBuildings = Mission(
80
- name="quadrant_buildings",
81
- description="Place buildings in the four quadrants of the map.",
82
- site=HELLO_WORLD,
83
- variants=[
84
- EmptyBaseVariant(),
85
- QuadrantBuildingsVariant(),
86
- ],
87
- )
88
-
89
- EasyHeartsMission = Mission(
90
- name="easy_hearts",
91
- description="Simplified heart crafting with generous caps and extractor base.",
92
- site=HELLO_WORLD,
93
- variants=[
94
- PackRatVariant(),
95
- ],
96
- )
97
-
98
50
 
99
- EVAL_MISSIONS: list[Mission] = [
100
- OxygenBottleneck,
51
+ EVAL_MISSIONS: list[CvCMission] = [
101
52
  EnergyStarved,
102
- DistantResources,
103
- QuadrantBuildings,
104
- EasyHeartsMission,
105
53
  ]
@@ -5,26 +5,24 @@ from __future__ import annotations
5
5
 
6
6
  import logging
7
7
 
8
- from cogames.cogs_vs_clips.mission import Mission, Site
9
- from cogames.cogs_vs_clips.procedural import MachinaArena
8
+ from cogames.cogs_vs_clips.mission import CvCMission
10
9
  from cogames.cogs_vs_clips.sites import HELLO_WORLD, TRAINING_FACILITY
10
+ from cogames.cogs_vs_clips.terrain import MachinaArena
11
11
  from cogames.cogs_vs_clips.variants import (
12
- CompassVariant,
13
12
  DarkSideVariant,
14
13
  DistantResourcesVariant,
15
14
  EmptyBaseVariant,
16
15
  EnergizedVariant,
17
- PackRatVariant,
18
16
  QuadrantBuildingsVariant,
19
- RoughTerrainVariant,
20
17
  SingleResourceUniformVariant,
21
18
  SuperChargedVariant,
22
19
  )
20
+ from cogames.core import CoGameSite
23
21
  from mettagrid.mapgen.mapgen import MapGen
24
22
 
25
23
  logger = logging.getLogger(__name__)
26
24
 
27
- SMALL_HELLO_WORLD = Site(
25
+ SMALL_HELLO_WORLD = CoGameSite(
28
26
  name="small_hello_world",
29
27
  description="Small hello world map.",
30
28
  map_builder=MapGen.Config(width=50, height=50, instance=MachinaArena.Config(spawn_count=20)),
@@ -32,7 +30,7 @@ SMALL_HELLO_WORLD = Site(
32
30
  max_cogs=20,
33
31
  )
34
32
 
35
- MEDIUM_HELLO_WORLD = Site(
33
+ MEDIUM_HELLO_WORLD = CoGameSite(
36
34
  name="medium_hello_world",
37
35
  description="Medium hello world map.",
38
36
  map_builder=MapGen.Config(width=100, height=100, instance=MachinaArena.Config(spawn_count=20)),
@@ -40,7 +38,7 @@ MEDIUM_HELLO_WORLD = Site(
40
38
  max_cogs=20,
41
39
  )
42
40
 
43
- LARGE_HELLO_WORLD = Site(
41
+ LARGE_HELLO_WORLD = CoGameSite(
44
42
  name="large_hello_world",
45
43
  description="Large hello world map.",
46
44
  map_builder=MapGen.Config(width=500, height=500, instance=MachinaArena.Config(spawn_count=20)),
@@ -49,19 +47,19 @@ LARGE_HELLO_WORLD = Site(
49
47
  )
50
48
 
51
49
  # Resource Bottleneck evals
52
- OxygenBottleneck = Mission(
50
+ OxygenBottleneck = CvCMission(
53
51
  name="oxygen_bottleneck",
54
52
  description="Oxygen is the limiting resource; agents must prioritize oxygen over other resources.",
55
53
  site=HELLO_WORLD,
56
54
  variants=[
57
55
  EmptyBaseVariant(missing=["oxygen_extractor"]),
58
56
  SingleResourceUniformVariant(building_name="oxygen_extractor"),
59
- PackRatVariant(),
57
+ EnergizedVariant(),
60
58
  ],
61
59
  )
62
60
 
63
61
  # Energy Starved evals
64
- EnergyStarved = Mission(
62
+ EnergyStarved = CvCMission(
65
63
  name="energy_starved",
66
64
  description="Energy is the limiting resource; agents must prioritize energy over other resources.",
67
65
  site=HELLO_WORLD,
@@ -74,17 +72,17 @@ EnergyStarved = Mission(
74
72
  # Curated difficulty tiers per mission
75
73
  # ------------------------------------------------------------
76
74
  # Oxygen Bottleneck
77
- OxygenBottleneckEasy = Mission(
75
+ OxygenBottleneckEasy = CvCMission(
78
76
  name="oxygen_bottleneck_easy",
79
77
  description="Easy: tuned oxygen focus with simple layout and generous capacities.",
80
78
  site=HELLO_WORLD,
81
79
  variants=[
82
80
  SingleResourceUniformVariant(building_name="oxygen_extractor"),
83
- PackRatVariant(),
81
+ EnergizedVariant(),
84
82
  ],
85
83
  )
86
84
 
87
- OxygenBottleneckStandard = Mission(
85
+ OxygenBottleneckStandard = CvCMission(
88
86
  name="oxygen_bottleneck_standard",
89
87
  description="Standard: oxygen is the bottleneck; extractor missing at base.",
90
88
  site=HELLO_WORLD,
@@ -93,18 +91,18 @@ OxygenBottleneckStandard = Mission(
93
91
  ],
94
92
  )
95
93
 
96
- OxygenBottleneckHard = Mission(
94
+ OxygenBottleneckHard = CvCMission(
97
95
  name="oxygen_bottleneck_hard",
98
- description="Hard: oxygen bottleneck plus rough terrain.",
96
+ description="Hard: oxygen bottleneck with dark side.",
99
97
  site=HELLO_WORLD,
100
98
  variants=[
101
99
  EmptyBaseVariant(missing=["oxygen_extractor"]),
102
- RoughTerrainVariant(),
100
+ DarkSideVariant(),
103
101
  ],
104
102
  )
105
103
 
106
104
  # Energy Starved
107
- EnergyStarvedEasy = Mission(
105
+ EnergyStarvedEasy = CvCMission(
108
106
  name="energy_starved_easy",
109
107
  description="Easy: abundant energy regen and capacity.",
110
108
  site=HELLO_WORLD,
@@ -114,7 +112,7 @@ EnergyStarvedEasy = Mission(
114
112
  ],
115
113
  )
116
114
 
117
- EnergyStarvedStandard = Mission(
115
+ EnergyStarvedStandard = CvCMission(
118
116
  name="energy_starved_standard",
119
117
  description="Standard: energy is the limiting resource with dark-side regen.",
120
118
  site=HELLO_WORLD,
@@ -123,18 +121,17 @@ EnergyStarvedStandard = Mission(
123
121
  ],
124
122
  )
125
123
 
126
- EnergyStarvedHard = Mission(
124
+ EnergyStarvedHard = CvCMission(
127
125
  name="energy_starved_hard",
128
- description="Hard: energy bottleneck with dark side and rough terrain.",
126
+ description="Hard: energy bottleneck with dark side.",
129
127
  site=HELLO_WORLD,
130
128
  variants=[
131
129
  DarkSideVariant(),
132
- RoughTerrainVariant(),
133
130
  ],
134
131
  )
135
132
 
136
133
  # Collect Distant Resources evals
137
- DistantResources = Mission(
134
+ DistantResources = CvCMission(
138
135
  name="distant_resources",
139
136
  description="Resources scattered far from base; heavy routing coordination.",
140
137
  site=HELLO_WORLD,
@@ -145,39 +142,37 @@ DistantResources = Mission(
145
142
  )
146
143
 
147
144
  # Distant Resources tiers
148
- DistantResourcesEasy = Mission(
145
+ DistantResourcesEasy = CvCMission(
149
146
  name="distant_resources_easy",
150
- description="Easy: simplified distribution and navigation aids.",
147
+ description="Easy: simplified distribution with generous capacity.",
151
148
  site=HELLO_WORLD,
152
149
  variants=[
153
- CompassVariant(),
154
- PackRatVariant(),
150
+ EnergizedVariant(),
155
151
  DistantResourcesVariant(),
156
152
  ],
157
153
  )
158
154
 
159
- DistantResourcesStandard = Mission(
155
+ DistantResourcesStandard = CvCMission(
160
156
  name="distant_resources_standard",
161
157
  description="Standard: resources scattered far from base.",
162
158
  site=HELLO_WORLD,
163
159
  variants=[
164
- CompassVariant(),
165
160
  DistantResourcesVariant(),
166
161
  ],
167
162
  )
168
163
 
169
- DistantResourcesHard = Mission(
164
+ DistantResourcesHard = CvCMission(
170
165
  name="distant_resources_hard",
171
- description="Hard: distant resources with rough terrain.",
166
+ description="Hard: distant resources with dark side.",
172
167
  site=HELLO_WORLD,
173
168
  variants=[
174
169
  DistantResourcesVariant(),
175
- RoughTerrainVariant(),
170
+ DarkSideVariant(),
176
171
  ],
177
172
  )
178
173
 
179
174
  # Divide and Conquer evals
180
- QuadrantBuildings = Mission(
175
+ QuadrantBuildings = CvCMission(
181
176
  name="quadrant_buildings",
182
177
  description="Place buildings in the four quadrants of the map.",
183
178
  site=HELLO_WORLD,
@@ -188,18 +183,17 @@ QuadrantBuildings = Mission(
188
183
  )
189
184
 
190
185
  # Quadrant Buildings tiers
191
- QuadrantBuildingsEasy = Mission(
186
+ QuadrantBuildingsEasy = CvCMission(
192
187
  name="quadrant_buildings_easy",
193
- description="Easy: buildings in quadrants with navigation aid and inventory boost.",
188
+ description="Easy: buildings in quadrants with energy boost.",
194
189
  site=HELLO_WORLD,
195
190
  variants=[
196
191
  QuadrantBuildingsVariant(),
197
- CompassVariant(),
198
- PackRatVariant(),
192
+ EnergizedVariant(),
199
193
  ],
200
194
  )
201
195
 
202
- QuadrantBuildingsStandard = Mission(
196
+ QuadrantBuildingsStandard = CvCMission(
203
197
  name="quadrant_buildings_standard",
204
198
  description="Standard: buildings placed in quadrants.",
205
199
  site=HELLO_WORLD,
@@ -209,54 +203,54 @@ QuadrantBuildingsStandard = Mission(
209
203
  ],
210
204
  )
211
205
 
212
- QuadrantBuildingsHard = Mission(
206
+ QuadrantBuildingsHard = CvCMission(
213
207
  name="quadrant_buildings_hard",
214
- description="Hard: quadrant distribution with empty base and rough terrain.",
208
+ description="Hard: quadrant distribution with empty base and dark side.",
215
209
  site=HELLO_WORLD,
216
210
  variants=[
217
211
  QuadrantBuildingsVariant(),
218
212
  EmptyBaseVariant(),
219
- RoughTerrainVariant(),
213
+ DarkSideVariant(),
220
214
  ],
221
215
  )
222
216
 
223
- EasyHeartsTraining = Mission(
217
+ EasyHeartsTraining = CvCMission(
224
218
  name="easy_hearts_training",
225
- description="Simplified heart crafting with generous caps and extractor base.",
219
+ description="Simplified heart crafting with generous energy.",
226
220
  site=TRAINING_FACILITY,
227
221
  variants=[
228
- PackRatVariant(),
222
+ EnergizedVariant(),
229
223
  ],
230
224
  )
231
225
 
232
- EasyHeartsSmallWorld = Mission(
226
+ EasyHeartsSmallWorld = CvCMission(
233
227
  name="easy_small_hearts",
234
- description="Simplified heart crafting with generous caps and extractor base.",
228
+ description="Simplified heart crafting with generous energy.",
235
229
  site=SMALL_HELLO_WORLD,
236
230
  variants=[
237
- PackRatVariant(),
231
+ EnergizedVariant(),
238
232
  ],
239
233
  )
240
234
 
241
- EasyHeartsMediumWorld = Mission(
235
+ EasyHeartsMediumWorld = CvCMission(
242
236
  name="easy_medium_hearts",
243
- description="Simplified heart crafting with generous caps and extractor base.",
237
+ description="Simplified heart crafting with generous energy.",
244
238
  site=MEDIUM_HELLO_WORLD,
245
239
  variants=[
246
- PackRatVariant(),
240
+ EnergizedVariant(),
247
241
  ],
248
242
  )
249
243
 
250
- EasyHeartsLargeWorld = Mission(
244
+ EasyHeartsLargeWorld = CvCMission(
251
245
  name="easy_large_hearts",
252
- description="Simplified heart crafting with generous caps and extractor base.",
246
+ description="Simplified heart crafting with generous energy.",
253
247
  site=LARGE_HELLO_WORLD,
254
248
  variants=[
255
- PackRatVariant(),
249
+ EnergizedVariant(),
256
250
  ],
257
251
  )
258
252
 
259
- EVAL_MISSIONS: list[Mission] = [
253
+ EVAL_MISSIONS: list[CvCMission] = [
260
254
  # Oxygen bottleneck tiers
261
255
  OxygenBottleneckEasy,
262
256
  OxygenBottleneckStandard,