cogames 0.3.49__py3-none-any.whl → 0.3.64__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 (169) hide show
  1. cogames/cli/client.py +60 -6
  2. cogames/cli/docsync/__init__.py +0 -0
  3. cogames/cli/docsync/_nb_md_directive_processing.py +180 -0
  4. cogames/cli/docsync/_nb_md_sync.py +103 -0
  5. cogames/cli/docsync/_nb_py_sync.py +122 -0
  6. cogames/cli/docsync/_three_way_sync.py +115 -0
  7. cogames/cli/docsync/_utils.py +76 -0
  8. cogames/cli/docsync/docsync.py +156 -0
  9. cogames/cli/leaderboard.py +112 -28
  10. cogames/cli/mission.py +64 -53
  11. cogames/cli/policy.py +46 -10
  12. cogames/cli/submit.py +268 -67
  13. cogames/cogs_vs_clips/cog.py +79 -0
  14. cogames/cogs_vs_clips/cogs_vs_clips_mapgen.md +19 -16
  15. cogames/cogs_vs_clips/cogsguard_reward_variants.py +153 -0
  16. cogames/cogs_vs_clips/cogsguard_tutorial.py +56 -0
  17. cogames/cogs_vs_clips/evals/README.md +10 -16
  18. cogames/cogs_vs_clips/evals/cogsguard_evals.py +81 -0
  19. cogames/cogs_vs_clips/evals/diagnostic_evals.py +49 -444
  20. cogames/cogs_vs_clips/evals/difficulty_variants.py +13 -326
  21. cogames/cogs_vs_clips/evals/integrated_evals.py +5 -45
  22. cogames/cogs_vs_clips/evals/spanning_evals.py +9 -180
  23. cogames/cogs_vs_clips/mission.py +187 -146
  24. cogames/cogs_vs_clips/missions.py +46 -137
  25. cogames/cogs_vs_clips/procedural.py +8 -8
  26. cogames/cogs_vs_clips/sites.py +107 -3
  27. cogames/cogs_vs_clips/stations.py +198 -186
  28. cogames/cogs_vs_clips/tutorial_missions.py +1 -1
  29. cogames/cogs_vs_clips/variants.py +25 -476
  30. cogames/device.py +13 -1
  31. cogames/{policy/scripted_agent/README.md → docs/SCRIPTED_AGENT.md} +82 -58
  32. cogames/evaluate.py +18 -30
  33. cogames/main.py +1434 -243
  34. cogames/maps/canidate1_1000.map +1 -1
  35. cogames/maps/canidate1_1000_stations.map +2 -2
  36. cogames/maps/canidate1_500.map +1 -1
  37. cogames/maps/canidate1_500_stations.map +2 -2
  38. cogames/maps/canidate2_1000.map +1 -1
  39. cogames/maps/canidate2_1000_stations.map +2 -2
  40. cogames/maps/canidate2_500.map +1 -1
  41. cogames/maps/canidate2_500_stations.map +2 -2
  42. cogames/maps/canidate3_1000.map +1 -1
  43. cogames/maps/canidate3_1000_stations.map +2 -2
  44. cogames/maps/canidate3_500.map +1 -1
  45. cogames/maps/canidate3_500_stations.map +2 -2
  46. cogames/maps/canidate4_500.map +1 -1
  47. cogames/maps/canidate4_500_stations.map +2 -2
  48. cogames/maps/cave_base_50.map +2 -2
  49. cogames/maps/diagnostic_evals/diagnostic_agile.map +2 -2
  50. cogames/maps/diagnostic_evals/diagnostic_agile_hard.map +2 -2
  51. cogames/maps/diagnostic_evals/diagnostic_charge_up.map +2 -2
  52. cogames/maps/diagnostic_evals/diagnostic_charge_up_hard.map +2 -2
  53. cogames/maps/diagnostic_evals/diagnostic_chest_navigation1.map +2 -2
  54. cogames/maps/diagnostic_evals/diagnostic_chest_navigation1_hard.map +2 -2
  55. cogames/maps/diagnostic_evals/diagnostic_chest_navigation2.map +2 -2
  56. cogames/maps/diagnostic_evals/diagnostic_chest_navigation2_hard.map +2 -2
  57. cogames/maps/diagnostic_evals/diagnostic_chest_navigation3.map +2 -2
  58. cogames/maps/diagnostic_evals/diagnostic_chest_navigation3_hard.map +2 -2
  59. cogames/maps/diagnostic_evals/diagnostic_chest_near.map +2 -2
  60. cogames/maps/diagnostic_evals/diagnostic_chest_search.map +2 -2
  61. cogames/maps/diagnostic_evals/diagnostic_chest_search_hard.map +2 -2
  62. cogames/maps/diagnostic_evals/diagnostic_extract_lab.map +2 -2
  63. cogames/maps/diagnostic_evals/diagnostic_extract_lab_hard.map +2 -2
  64. cogames/maps/diagnostic_evals/diagnostic_memory.map +2 -2
  65. cogames/maps/diagnostic_evals/diagnostic_memory_hard.map +2 -2
  66. cogames/maps/diagnostic_evals/diagnostic_radial.map +2 -2
  67. cogames/maps/diagnostic_evals/diagnostic_radial_hard.map +2 -2
  68. cogames/maps/diagnostic_evals/diagnostic_resource_lab.map +2 -2
  69. cogames/maps/diagnostic_evals/diagnostic_unclip.map +2 -2
  70. cogames/maps/evals/eval_balanced_spread.map +9 -5
  71. cogames/maps/evals/eval_clip_oxygen.map +9 -5
  72. cogames/maps/evals/eval_collect_resources.map +9 -5
  73. cogames/maps/evals/eval_collect_resources_hard.map +9 -5
  74. cogames/maps/evals/eval_collect_resources_medium.map +9 -5
  75. cogames/maps/evals/eval_divide_and_conquer.map +9 -5
  76. cogames/maps/evals/eval_energy_starved.map +9 -5
  77. cogames/maps/evals/eval_multi_coordinated_collect_hard.map +9 -5
  78. cogames/maps/evals/eval_oxygen_bottleneck.map +9 -5
  79. cogames/maps/evals/eval_single_use_world.map +9 -5
  80. cogames/maps/evals/extractor_hub_100x100.map +9 -5
  81. cogames/maps/evals/extractor_hub_30x30.map +9 -5
  82. cogames/maps/evals/extractor_hub_50x50.map +9 -5
  83. cogames/maps/evals/extractor_hub_70x70.map +9 -5
  84. cogames/maps/evals/extractor_hub_80x80.map +9 -5
  85. cogames/maps/machina_100_stations.map +2 -2
  86. cogames/maps/machina_200_stations.map +2 -2
  87. cogames/maps/machina_200_stations_small.map +2 -2
  88. cogames/maps/machina_eval_exp01.map +2 -2
  89. cogames/maps/machina_eval_template_large.map +2 -2
  90. cogames/maps/machinatrainer4agents.map +2 -2
  91. cogames/maps/machinatrainer4agentsbase.map +2 -2
  92. cogames/maps/machinatrainerbig.map +2 -2
  93. cogames/maps/machinatrainersmall.map +2 -2
  94. cogames/maps/planky_evals/aligner_avoid_aoe.map +28 -0
  95. cogames/maps/planky_evals/aligner_full_cycle.map +28 -0
  96. cogames/maps/planky_evals/aligner_gear.map +24 -0
  97. cogames/maps/planky_evals/aligner_hearts.map +24 -0
  98. cogames/maps/planky_evals/aligner_junction.map +26 -0
  99. cogames/maps/planky_evals/exploration_distant.map +28 -0
  100. cogames/maps/planky_evals/maze.map +32 -0
  101. cogames/maps/planky_evals/miner_best_resource.map +26 -0
  102. cogames/maps/planky_evals/miner_deposit.map +24 -0
  103. cogames/maps/planky_evals/miner_extract.map +26 -0
  104. cogames/maps/planky_evals/miner_full_cycle.map +28 -0
  105. cogames/maps/planky_evals/miner_gear.map +24 -0
  106. cogames/maps/planky_evals/multi_role.map +28 -0
  107. cogames/maps/planky_evals/resource_chain.map +30 -0
  108. cogames/maps/planky_evals/scout_explore.map +32 -0
  109. cogames/maps/planky_evals/scout_gear.map +24 -0
  110. cogames/maps/planky_evals/scrambler_full_cycle.map +28 -0
  111. cogames/maps/planky_evals/scrambler_gear.map +24 -0
  112. cogames/maps/planky_evals/scrambler_target.map +26 -0
  113. cogames/maps/planky_evals/stuck_corridor.map +32 -0
  114. cogames/maps/planky_evals/survive_retreat.map +26 -0
  115. cogames/maps/training_facility_clipped.map +2 -2
  116. cogames/maps/training_facility_open_1.map +2 -2
  117. cogames/maps/training_facility_open_2.map +2 -2
  118. cogames/maps/training_facility_open_3.map +2 -2
  119. cogames/maps/training_facility_tight_4.map +2 -2
  120. cogames/maps/training_facility_tight_5.map +2 -2
  121. cogames/maps/vanilla_large.map +2 -2
  122. cogames/maps/vanilla_small.map +2 -2
  123. cogames/pickup.py +183 -0
  124. cogames/play.py +166 -33
  125. cogames/policy/chaos_monkey.py +54 -0
  126. cogames/policy/nim_agents/__init__.py +27 -10
  127. cogames/policy/nim_agents/agents.py +121 -60
  128. cogames/policy/nim_agents/thinky_eval.py +35 -222
  129. cogames/policy/pufferlib_policy.py +67 -32
  130. cogames/policy/starter_agent.py +184 -0
  131. cogames/policy/trainable_policy_template.py +4 -1
  132. cogames/train.py +51 -13
  133. cogames/verbose.py +2 -2
  134. cogames-0.3.64.dist-info/METADATA +1842 -0
  135. cogames-0.3.64.dist-info/RECORD +159 -0
  136. cogames-0.3.64.dist-info/licenses/LICENSE +21 -0
  137. cogames-0.3.64.dist-info/top_level.txt +2 -0
  138. metta_alo/__init__.py +0 -0
  139. metta_alo/job_specs.py +17 -0
  140. metta_alo/policy.py +16 -0
  141. metta_alo/pure_single_episode_runner.py +75 -0
  142. metta_alo/py.typed +0 -0
  143. metta_alo/rollout.py +322 -0
  144. metta_alo/scoring.py +168 -0
  145. cogames/maps/diagnostic_evals/diagnostic_assembler_near.map +0 -49
  146. cogames/maps/diagnostic_evals/diagnostic_assembler_search.map +0 -49
  147. cogames/maps/diagnostic_evals/diagnostic_assembler_search_hard.map +0 -89
  148. cogames/policy/nim_agents/common.nim +0 -887
  149. cogames/policy/nim_agents/install.sh +0 -1
  150. cogames/policy/nim_agents/ladybug_agent.nim +0 -984
  151. cogames/policy/nim_agents/nim_agents.nim +0 -55
  152. cogames/policy/nim_agents/nim_agents.nims +0 -14
  153. cogames/policy/nim_agents/nimby.lock +0 -3
  154. cogames/policy/nim_agents/racecar_agents.nim +0 -884
  155. cogames/policy/nim_agents/random_agents.nim +0 -68
  156. cogames/policy/nim_agents/test_agents.py +0 -53
  157. cogames/policy/nim_agents/thinky_agents.nim +0 -717
  158. cogames/policy/scripted_agent/baseline_agent.py +0 -1049
  159. cogames/policy/scripted_agent/demo_policy.py +0 -244
  160. cogames/policy/scripted_agent/pathfinding.py +0 -126
  161. cogames/policy/scripted_agent/starter_agent.py +0 -136
  162. cogames/policy/scripted_agent/types.py +0 -235
  163. cogames/policy/scripted_agent/unclipping_agent.py +0 -476
  164. cogames/policy/scripted_agent/utils.py +0 -385
  165. cogames-0.3.49.dist-info/METADATA +0 -406
  166. cogames-0.3.49.dist-info/RECORD +0 -136
  167. cogames-0.3.49.dist-info/top_level.txt +0 -1
  168. {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/WHEEL +0 -0
  169. {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/entry_points.txt +0 -0
@@ -1,43 +1,50 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from abc import ABC
4
- from typing import override
4
+ from typing import TypeVar, override
5
5
 
6
6
  from pydantic import Field
7
+ from typing_extensions import Self
7
8
 
9
+ from cogames.cogs_vs_clips.cog import CogConfig
8
10
  from cogames.cogs_vs_clips.stations import (
9
- CarbonExtractorConfig,
10
- ChargerConfig,
11
- CvCAssemblerConfig,
12
- CvCChestConfig,
11
+ ELEMENTS,
12
+ GEAR,
13
+ CogsGuardChestConfig,
13
14
  CvCWallConfig,
14
- GermaniumExtractorConfig,
15
- OxygenExtractorConfig,
16
- SiliconExtractorConfig,
17
- resources,
15
+ GearStationConfig,
16
+ HubConfig,
17
+ JunctionConfig,
18
+ SimpleExtractorConfig,
18
19
  )
19
20
  from mettagrid.base_config import Config
20
- from mettagrid.config import vibes
21
- from mettagrid.config.mettagrid_config import (
21
+ from mettagrid.config.action_config import (
22
22
  ActionsConfig,
23
- AgentConfig,
24
- AgentRewards,
25
23
  ChangeVibeActionConfig,
26
- ClipperConfig,
24
+ MoveActionConfig,
25
+ NoopActionConfig,
26
+ )
27
+ from mettagrid.config.event_config import EventConfig, periodic
28
+ from mettagrid.config.filter import isAlignedTo, isNear
29
+ from mettagrid.config.game_value import inv
30
+ from mettagrid.config.game_value import stat as game_stat
31
+ from mettagrid.config.mettagrid_config import (
32
+ CollectiveConfig,
27
33
  GameConfig,
28
- GlobalObsConfig,
29
34
  InventoryConfig,
30
35
  MettaGridConfig,
31
- MoveActionConfig,
32
- NoopActionConfig,
33
- ProtocolConfig,
34
36
  ResourceLimitsConfig,
35
- TransferActionConfig,
36
- VibeTransfer,
37
37
  )
38
+ from mettagrid.config.mutation import alignTo
39
+ from mettagrid.config.obs_config import GlobalObsConfig, ObsConfig
40
+ from mettagrid.config.reward_config import numObjects, reward
41
+ from mettagrid.config.tag import typeTag
38
42
  from mettagrid.config.vibes import Vibe
39
43
  from mettagrid.map_builder.map_builder import AnyMapBuilderConfig
40
44
 
45
+ # Type variable for mission types
46
+ TMission = TypeVar("TMission", bound="MissionBase")
47
+
41
48
 
42
49
  class MissionVariant(Config, ABC):
43
50
  # Note: we could derive the name from the class name automatically, but it would make it
@@ -45,17 +52,17 @@ class MissionVariant(Config, ABC):
45
52
  name: str
46
53
  description: str = Field(default="")
47
54
 
48
- def modify_mission(self, mission: Mission) -> None:
55
+ def modify_mission(self, mission: MissionBase) -> None:
49
56
  # Override this method to modify the mission.
50
57
  # Variants are allowed to modify the mission in-place - it's guaranteed to be a one-time only instance.
51
58
  pass
52
59
 
53
- def modify_env(self, mission: Mission, env: MettaGridConfig) -> None:
60
+ def modify_env(self, mission: MissionBase, env: MettaGridConfig) -> None:
54
61
  # Override this method to modify the produced environment.
55
62
  # Variants are allowed to modify the environment in-place.
56
63
  pass
57
64
 
58
- def compat(self, mission: Mission) -> bool:
65
+ def compat(self, mission: MissionBase) -> bool:
59
66
  """Check if this variant is compatible with the given mission.
60
67
 
61
68
  Returns True if the variant can be safely applied to the mission.
@@ -63,7 +70,7 @@ class MissionVariant(Config, ABC):
63
70
  """
64
71
  return True
65
72
 
66
- def apply(self, mission: Mission) -> Mission:
73
+ def apply(self, mission: TMission) -> TMission:
67
74
  mission = mission.model_copy(deep=True)
68
75
  mission.variants.append(self)
69
76
  self.modify_mission(mission)
@@ -107,8 +114,8 @@ class Site(Config):
107
114
  MAP_MISSION_DELIMITER = "."
108
115
 
109
116
 
110
- class Mission(Config):
111
- """Mission configuration for Cogs vs Clips."""
117
+ class MissionBase(Config, ABC):
118
+ """Base class for Mission configurations with common fields and methods."""
112
119
 
113
120
  name: str
114
121
  description: str
@@ -118,27 +125,7 @@ class Mission(Config):
118
125
  # Variants are applied to the mission immediately, and to its env when make_env is called
119
126
  variants: list[MissionVariant] = Field(default_factory=list)
120
127
 
121
- carbon_extractor: CarbonExtractorConfig = Field(default_factory=CarbonExtractorConfig)
122
- oxygen_extractor: OxygenExtractorConfig = Field(default_factory=OxygenExtractorConfig)
123
- germanium_extractor: GermaniumExtractorConfig = Field(default_factory=GermaniumExtractorConfig)
124
- silicon_extractor: SiliconExtractorConfig = Field(default_factory=SiliconExtractorConfig)
125
- charger: ChargerConfig = Field(default_factory=ChargerConfig)
126
- chest: CvCChestConfig = Field(default_factory=CvCChestConfig)
127
- wall: CvCWallConfig = Field(default_factory=CvCWallConfig)
128
- assembler: CvCAssemblerConfig = Field(default_factory=CvCAssemblerConfig)
129
-
130
- clip_period: int = Field(default=0)
131
- cargo_capacity: int = Field(default=100)
132
- energy_capacity: int = Field(default=100)
133
- energy_regen_amount: int = Field(default=1)
134
- inventory_regen_interval: int = Field(default=1)
135
- gear_capacity: int = Field(default=5)
136
- move_energy_cost: int = Field(default=2)
137
- heart_capacity: int = Field(default=1)
138
- # Control vibe swapping in variants
139
- enable_vibe_change: bool = Field(default=True)
140
- vibes: list[Vibe] | None = Field(default=None)
141
- compass_enabled: bool = Field(default=True)
128
+ max_steps: int = Field(default=10000)
142
129
 
143
130
  def __init__(self, **kwargs):
144
131
  super().__init__(**kwargs)
@@ -146,7 +133,7 @@ class Mission(Config):
146
133
  for variant in self.variants:
147
134
  variant.modify_mission(self)
148
135
 
149
- def with_variants(self, variants: list[MissionVariant]) -> Mission:
136
+ def with_variants(self, variants: list[MissionVariant]) -> Self:
150
137
  mission = self
151
138
  for variant in variants:
152
139
  mission = variant.apply(mission)
@@ -155,6 +142,48 @@ class Mission(Config):
155
142
  def full_name(self) -> str:
156
143
  return f"{self.site.name}{MAP_MISSION_DELIMITER}{self.name}"
157
144
 
145
+
146
+ # CogsGuard vibes
147
+ COGSGUARD_VIBES = [
148
+ Vibe("😐", "default"),
149
+ Vibe("❤️", "heart"),
150
+ Vibe("⚙️", "gear"),
151
+ Vibe("🌀", "scrambler"),
152
+ Vibe("🔗", "aligner"),
153
+ Vibe("⛏️", "miner"),
154
+ Vibe("🔭", "scout"),
155
+ ]
156
+
157
+
158
+ class Mission(MissionBase):
159
+ """Mission configuration for CogsGuard game mode."""
160
+
161
+ # Agent configuration
162
+ cog: CogConfig = Field(default_factory=CogConfig)
163
+
164
+ wealth: int = Field(default=1)
165
+
166
+ # Collective initial resources
167
+ collective_initial_carbon: int = Field(default=10)
168
+ collective_initial_oxygen: int = Field(default=10)
169
+ collective_initial_germanium: int = Field(default=10)
170
+ collective_initial_silicon: int = Field(default=10)
171
+ collective_initial_heart: int = Field(default=5)
172
+
173
+ # Clips Behavior - scramble cogs junctions to neutral
174
+ # Note: must start after initial_clips fires at timestep 10 (events fire alphabetically)
175
+ clips_scramble_start: int = Field(default=50)
176
+ clips_scramble_interval: int = Field(default=100)
177
+ clips_scramble_radius: int = Field(default=25)
178
+
179
+ # Clips Behavior - align neutral junctions to clips
180
+ clips_align_start: int = Field(default=100)
181
+ clips_align_interval: int = Field(default=100)
182
+ clips_align_radius: int = Field(default=25)
183
+
184
+ # Station configs
185
+ wall: CvCWallConfig = Field(default_factory=CvCWallConfig)
186
+
158
187
  def make_env(self) -> MettaGridConfig:
159
188
  """Create a MettaGridConfig from this mission.
160
189
 
@@ -166,119 +195,125 @@ class Mission(Config):
166
195
  map_builder = self.site.map_builder
167
196
  num_cogs = self.num_cogs if self.num_cogs is not None else self.site.min_cogs
168
197
 
198
+ gear = GEAR
199
+ elements = ELEMENTS
200
+ resources_list = ["energy", "heart", "hp", "influence", *elements, *gear]
201
+ vibe_names = [vibe.name for vibe in COGSGUARD_VIBES]
202
+
203
+ extractor_objects = {
204
+ f"{resource}_extractor": SimpleExtractorConfig(resource=resource).station_cfg() for resource in elements
205
+ }
206
+ gear_objects = {f"{g}_station": GearStationConfig(gear_type=g).station_cfg() for g in gear}
207
+
208
+ # Create inventory observations for collective resources
209
+ collective_obs = [inv(f"collective.{resource}") for resource in elements]
210
+
169
211
  game = GameConfig(
170
212
  map_builder=map_builder,
213
+ max_steps=self.max_steps,
171
214
  num_agents=num_cogs,
172
- resource_names=resources,
173
- vibe_names=[vibe.name for vibe in vibes.VIBES],
174
- global_obs=GlobalObsConfig(compass=self.compass_enabled, goal_obs=True),
215
+ resource_names=resources_list,
216
+ vibe_names=vibe_names,
217
+ obs=ObsConfig(global_obs=GlobalObsConfig(obs=collective_obs, local_position=True)),
175
218
  actions=ActionsConfig(
176
- move=MoveActionConfig(consumed_resources={"energy": self.move_energy_cost}),
219
+ move=MoveActionConfig(consumed_resources={"energy": self.cog.move_energy_cost}),
177
220
  noop=NoopActionConfig(),
178
- change_vibe=ChangeVibeActionConfig(
179
- vibes=(
180
- []
181
- if not self.enable_vibe_change
182
- else (self.vibes if self.vibes is not None else list(vibes.VIBES))
183
- )
184
- ),
185
- transfer=TransferActionConfig(
186
- enabled=True,
187
- vibe_transfers=[VibeTransfer(vibe="charger", target={"energy": 20}, actor={"energy": -20})],
188
- ),
221
+ change_vibe=ChangeVibeActionConfig(vibes=COGSGUARD_VIBES),
189
222
  ),
190
- agent=AgentConfig(
191
- inventory=InventoryConfig(
192
- limits={
193
- "heart": ResourceLimitsConfig(limit=self.heart_capacity, resources=["heart"]),
194
- "energy": ResourceLimitsConfig(limit=self.energy_capacity, resources=["energy"]),
195
- "cargo": ResourceLimitsConfig(
196
- limit=self.cargo_capacity, resources=["carbon", "oxygen", "germanium", "silicon"]
197
- ),
198
- "gear": ResourceLimitsConfig(
199
- limit=self.gear_capacity, resources=["scrambler", "modulator", "decoder", "resonator"]
223
+ agent=self.cog.agent_config(gear=gear, elements=elements).model_copy(
224
+ update={
225
+ "rewards": {
226
+ "aligned_junction_held": reward(
227
+ game_stat("collective.aligned.junction.held"),
228
+ weight=1.0 / self.max_steps,
229
+ denoms=[numObjects("junction")],
200
230
  ),
201
231
  },
202
- initial={"energy": self.energy_capacity},
203
- regen_amounts={"default": {"energy": self.energy_regen_amount}},
204
- ),
205
- rewards=AgentRewards(
206
- # Reward only the agent that deposits a heart.
207
- stats={"chest.heart.deposited_by_agent": 1.0},
208
- ),
209
- diversity_tracked_resources=["energy", "carbon", "oxygen", "germanium", "silicon", "heart"],
210
- ),
211
- inventory_regen_interval=self.inventory_regen_interval,
212
- clipper=ClipperConfig(
213
- unclipping_protocols=[
214
- ProtocolConfig(
215
- input_resources={"decoder": 1},
216
- cooldown=1,
217
- ),
218
- ProtocolConfig(
219
- input_resources={"modulator": 1},
220
- cooldown=1,
221
- ),
222
- ProtocolConfig(
223
- input_resources={"scrambler": 1},
224
- cooldown=1,
225
- ),
226
- ProtocolConfig(
227
- input_resources={"resonator": 1},
228
- cooldown=1,
229
- ),
230
- ],
231
- clip_period=self.clip_period,
232
+ }
232
233
  ),
233
234
  objects={
234
235
  "wall": self.wall.station_cfg(),
235
- "assembler": self.assembler.station_cfg(),
236
- "chest": self.chest.station_cfg(),
237
- "charger": self.charger.station_cfg(),
238
- "carbon_extractor": self.carbon_extractor.station_cfg(),
239
- "oxygen_extractor": self.oxygen_extractor.station_cfg(),
240
- "germanium_extractor": self.germanium_extractor.station_cfg(),
241
- "silicon_extractor": self.silicon_extractor.station_cfg(),
242
- # Resource-specific chests used by diagnostic missions
243
- # These use simplified vibe_transfers (only "default") to avoid issues when vibes are restricted
244
- "chest_carbon": self.chest.station_cfg().model_copy(
245
- update={
246
- "map_name": "chest_carbon",
247
- "vibe_transfers": {"default": {"carbon": 255}},
248
- }
236
+ "hub": HubConfig(map_name="hub", team="cogs").station_cfg(),
237
+ "junction": JunctionConfig(map_name="junction").station_cfg(),
238
+ "chest": CogsGuardChestConfig().station_cfg(),
239
+ **extractor_objects,
240
+ **gear_objects,
241
+ },
242
+ collectives={
243
+ "cogs": CollectiveConfig(
244
+ inventory=InventoryConfig(
245
+ limits={
246
+ "resources": ResourceLimitsConfig(min=10000, resources=elements),
247
+ "hearts": ResourceLimitsConfig(min=65535, resources=["heart"]),
248
+ },
249
+ initial={
250
+ "carbon": self.collective_initial_carbon * self.wealth,
251
+ "oxygen": self.collective_initial_oxygen * self.wealth,
252
+ "germanium": self.collective_initial_germanium * self.wealth,
253
+ "silicon": self.collective_initial_silicon * self.wealth,
254
+ "heart": self.collective_initial_heart * self.wealth,
255
+ },
256
+ ),
249
257
  ),
250
- "chest_oxygen": self.chest.station_cfg().model_copy(
251
- update={
252
- "map_name": "chest_oxygen",
253
- "vibe_transfers": {"default": {"oxygen": 255}},
254
- }
258
+ "clips": CollectiveConfig(),
259
+ },
260
+ events={
261
+ "initial_clips": EventConfig(
262
+ name="initial_clips",
263
+ target_tag=typeTag("junction"),
264
+ timesteps=[10],
265
+ mutations=[alignTo("clips")],
266
+ max_targets=1,
255
267
  ),
256
- "chest_germanium": self.chest.station_cfg().model_copy(
257
- update={
258
- "map_name": "chest_germanium",
259
- "vibe_transfers": {"default": {"germanium": 255}},
260
- }
268
+ "cogs_to_neutral": EventConfig(
269
+ name="cogs_to_neutral",
270
+ target_tag=typeTag("junction"),
271
+ timesteps=periodic(
272
+ start=self.clips_scramble_start,
273
+ period=self.clips_scramble_interval,
274
+ end_period=self.clips_scramble_interval // 5,
275
+ end=self.max_steps,
276
+ ),
277
+ filters=[
278
+ isNear(typeTag("junction"), [isAlignedTo("clips")], radius=self.clips_scramble_radius),
279
+ isAlignedTo("cogs"),
280
+ ],
281
+ mutations=[alignTo(None)],
282
+ max_targets=1,
261
283
  ),
262
- "chest_silicon": self.chest.station_cfg().model_copy(
263
- update={
264
- "map_name": "chest_silicon",
265
- "vibe_transfers": {"default": {"silicon": 255}},
266
- }
284
+ "neutral_to_clips": EventConfig(
285
+ name="neutral_to_clips",
286
+ target_tag=typeTag("junction"),
287
+ timesteps=periodic(
288
+ start=self.clips_align_start,
289
+ period=self.clips_align_interval,
290
+ end_period=self.clips_align_interval // 5,
291
+ end=self.max_steps,
292
+ ),
293
+ filters=[
294
+ isNear(typeTag("junction"), [isAlignedTo("clips")], radius=self.clips_align_radius),
295
+ isAlignedTo(None),
296
+ ],
297
+ mutations=[alignTo("clips")],
298
+ max_targets=1,
299
+ fallback="cogs_to_neutral",
300
+ ),
301
+ # If the Clips can't find any junctions near them, align a random junction
302
+ "presence_check": EventConfig(
303
+ name="presence_check",
304
+ target_tag=typeTag("junction"),
305
+ timesteps=periodic(
306
+ start=self.clips_scramble_start,
307
+ period=self.clips_scramble_interval,
308
+ end=self.max_steps,
309
+ ),
310
+ filters=[
311
+ isNear(typeTag("junction"), [isAlignedTo("clips")], radius=self.clips_scramble_radius),
312
+ ],
313
+ mutations=[],
314
+ max_targets=1,
315
+ fallback="initial_clips",
267
316
  ),
268
- # Clipped variants with unique map_names so they don't conflict with regular extractors
269
- # These are used by maps that explicitly place clipped extractors
270
- "clipped_carbon_extractor": self.carbon_extractor.model_copy(update={"start_clipped": True})
271
- .station_cfg()
272
- .model_copy(update={"map_name": "clipped_carbon_extractor"}),
273
- "clipped_oxygen_extractor": self.oxygen_extractor.model_copy(update={"start_clipped": True})
274
- .station_cfg()
275
- .model_copy(update={"map_name": "clipped_oxygen_extractor"}),
276
- "clipped_germanium_extractor": self.germanium_extractor.model_copy(update={"start_clipped": True})
277
- .station_cfg()
278
- .model_copy(update={"map_name": "clipped_germanium_extractor"}),
279
- "clipped_silicon_extractor": self.silicon_extractor.model_copy(update={"start_clipped": True})
280
- .station_cfg()
281
- .model_copy(update={"map_name": "clipped_silicon_extractor"}),
282
317
  },
283
318
  )
284
319
 
@@ -293,3 +328,9 @@ class Mission(Config):
293
328
  env.label += f".{variant.name}"
294
329
 
295
330
  return env
331
+
332
+
333
+ # Backwards compatibility alias
334
+ CogsGuardMission = Mission
335
+
336
+ AnyMission = Mission
@@ -1,166 +1,78 @@
1
1
  from functools import lru_cache
2
2
 
3
- from cogames.cogs_vs_clips.mission import Mission
4
- from cogames.cogs_vs_clips.mission_utils import get_map
5
- from cogames.cogs_vs_clips.sites import HELLO_WORLD, MACHINA_1, TRAINING_FACILITY
6
- from cogames.cogs_vs_clips.variants import (
7
- AssemblerDrawsFromChestsVariant,
8
- BalancedCornersVariant,
9
- ClipHubStationsVariant,
10
- ClipPeriodOnVariant,
11
- EmptyBaseVariant,
12
- ExtractorHeartTuneVariant,
13
- HeartChorusVariant,
14
- InventoryHeartTuneVariant,
15
- LonelyHeartVariant,
16
- PackRatVariant,
17
- SharedRewardsVariant,
18
- VibeCheckMin2Variant,
3
+ from cogames.cogs_vs_clips.mission import AnyMission, Mission
4
+ from cogames.cogs_vs_clips.sites import (
5
+ COGSGUARD_ARENA,
6
+ COGSGUARD_MACHINA_1,
7
+ make_cogsguard_machina1_site,
19
8
  )
20
9
  from mettagrid.config.mettagrid_config import MettaGridConfig
21
10
 
22
- # Training Facility Missions
11
+ # CogsGuard Missions
23
12
 
24
- HarvestMission = Mission(
25
- name="harvest",
26
- description="Collect resources, assemble hearts, and deposit them in the chest. Make sure to stay charged!",
27
- site=TRAINING_FACILITY,
28
- variants=[ExtractorHeartTuneVariant(hearts=10), PackRatVariant(), LonelyHeartVariant()],
29
- )
30
-
31
- VibeCheckMission = Mission(
32
- name="vibe_check",
33
- description="Modulate the group vibe to assemble HEARTs.",
34
- site=TRAINING_FACILITY,
35
- num_cogs=4,
36
- variants=[VibeCheckMin2Variant(), ExtractorHeartTuneVariant(hearts=10)],
37
- )
38
-
39
-
40
- RepairMission = Mission(
41
- name="repair",
42
- description="Repair disabled stations to restore their functionality.",
43
- site=TRAINING_FACILITY,
44
- num_cogs=2,
45
- variants=[
46
- InventoryHeartTuneVariant(hearts=1),
47
- ExtractorHeartTuneVariant(hearts=10),
48
- LonelyHeartVariant(),
49
- ClipPeriodOnVariant(),
50
- ClipHubStationsVariant(),
51
- ],
52
- ) # If you get only two hearts you failed.
53
-
54
-
55
- # Easy Hearts: simplified heart crafting and generous limits with extractor hub
56
- EasyHeartsTrainingMission = Mission(
57
- name="easy_hearts_training_facility",
58
- description="Simplified heart crafting with generous caps and extractor base.",
59
- site=TRAINING_FACILITY,
60
- variants=[
61
- LonelyHeartVariant(),
62
- HeartChorusVariant(),
63
- PackRatVariant(),
64
- ],
65
- )
66
-
67
- # Easy Hearts: simplified heart crafting and generous limits with extractor hub
68
- EasyHeartsHelloWorldMission = Mission(
69
- name="easy_hearts_hello_world",
70
- description="Simplified heart crafting with generous caps and extractor base.",
71
- site=HELLO_WORLD,
72
- variants=[
73
- LonelyHeartVariant(),
74
- HeartChorusVariant(),
75
- PackRatVariant(),
76
- ],
77
- )
78
13
 
14
+ def make_cogsguard_mission(num_agents: int = 10, max_steps: int = 10000) -> Mission:
15
+ """Create a CogsGuard mission with configurable parameters (Machina1 layout)."""
16
+ return Mission(
17
+ name="basic",
18
+ description="Basic CogsGuard mission (Machina1 layout)",
19
+ site=make_cogsguard_machina1_site(num_agents),
20
+ num_cogs=num_agents,
21
+ max_steps=max_steps,
22
+ )
79
23
 
80
- # Hello World Missions
81
24
 
82
- HelloWorldOpenWorldMission = Mission(
83
- name="open_world",
84
- description="Collect resources and assemble HEARTs.",
85
- site=HELLO_WORLD,
86
- variants=[EmptyBaseVariant()],
25
+ CogsGuardMachina1Mission = Mission(
26
+ name="basic",
27
+ description="CogsGuard Machina1 - compete to control junctions with gear abilities.",
28
+ site=COGSGUARD_MACHINA_1,
29
+ num_cogs=8,
30
+ max_steps=10000,
87
31
  )
88
32
 
89
-
90
- # Machina 1 Missions
91
- Machina1OpenWorldMission = Mission(
92
- name="open_world",
93
- description="Collect resources and assemble HEARTs.",
94
- site=MACHINA_1,
95
- variants=[EmptyBaseVariant()],
33
+ CogsGuardBasicMission = Mission(
34
+ name="basic",
35
+ description="CogsGuard Arena - compact training map with gear abilities.",
36
+ site=COGSGUARD_ARENA,
37
+ num_cogs=8,
38
+ max_steps=1000,
96
39
  )
97
40
 
98
- Machina1OpenWorldWithChestsMission = Mission(
99
- name="open_world_with_chests",
100
- description="Collect resources and assemble HEARTs.",
101
- site=MACHINA_1,
102
- variants=[EmptyBaseVariant(), AssemblerDrawsFromChestsVariant()],
103
- )
104
41
 
105
- Machina1BalancedCornersMission = Mission(
106
- name="balanced_corners",
107
- description="Collect resources and assemble HEARTs. Map has balanced corner distances for fair spawns.",
108
- site=MACHINA_1,
109
- variants=[EmptyBaseVariant(), BalancedCornersVariant()],
110
- )
111
-
112
- Machina1OpenWorldSharedRewardsMission = Mission(
113
- name="open_world_shared_rewards",
114
- description="Collect resources and assemble HEARTs. Rewards for deposited hearts are shared among all agents.",
115
- site=MACHINA_1,
116
- variants=[EmptyBaseVariant(), SharedRewardsVariant()],
117
- )
42
+ _CORE_MISSIONS: list[AnyMission] = [
43
+ CogsGuardMachina1Mission,
44
+ CogsGuardBasicMission,
45
+ ]
118
46
 
119
47
 
120
- HelloWorldUnclipMission = Mission(
121
- name="hello_world_unclip",
122
- description="Stabilize clipped extractors scattered across the hello_world sector.",
123
- site=HELLO_WORLD,
124
- num_cogs=4,
125
- variants=[ClipPeriodOnVariant(), InventoryHeartTuneVariant(hearts=1), ClipHubStationsVariant()],
126
- )
127
-
48
+ def get_core_missions() -> list[AnyMission]:
49
+ return list(_CORE_MISSIONS)
128
50
 
129
- _CORE_MISSIONS: list[Mission] = [
130
- HarvestMission,
131
- VibeCheckMission,
132
- RepairMission,
133
- EasyHeartsTrainingMission,
134
- EasyHeartsHelloWorldMission,
135
- HelloWorldUnclipMission,
136
- HelloWorldOpenWorldMission,
137
- Machina1OpenWorldMission,
138
- Machina1OpenWorldWithChestsMission,
139
- Machina1BalancedCornersMission,
140
- Machina1OpenWorldSharedRewardsMission,
141
- ]
142
51
 
52
+ def get_legacy_missions() -> list[Mission]:
53
+ """Get legacy (pre-CogsGuard) missions for backward compatibility.
143
54
 
144
- def get_core_missions() -> list[Mission]:
145
- return list(_CORE_MISSIONS)
55
+ Legacy missions have been removed. Returns empty list.
56
+ """
57
+ return []
146
58
 
147
59
 
148
- def _build_eval_missions() -> list[Mission]:
149
- from cogames.cogs_vs_clips.evals.diagnostic_evals import DIAGNOSTIC_EVALS
60
+ def _build_eval_missions() -> list[AnyMission]:
61
+ from cogames.cogs_vs_clips.evals.cogsguard_evals import COGSGUARD_EVAL_MISSIONS
150
62
  from cogames.cogs_vs_clips.evals.integrated_evals import EVAL_MISSIONS as INTEGRATED_EVAL_MISSIONS
151
63
 
152
64
  return [
65
+ *COGSGUARD_EVAL_MISSIONS,
153
66
  *INTEGRATED_EVAL_MISSIONS,
154
- *[mission_cls() for mission_cls in DIAGNOSTIC_EVALS], # type: ignore[call-arg]
155
67
  ]
156
68
 
157
69
 
158
70
  @lru_cache(maxsize=1)
159
- def get_missions() -> list[Mission]:
71
+ def get_missions() -> list[AnyMission]:
160
72
  return [*_CORE_MISSIONS, *_build_eval_missions()]
161
73
 
162
74
 
163
- def __getattr__(name: str) -> list[Mission]:
75
+ def __getattr__(name: str) -> list[AnyMission]:
164
76
  if name == "MISSIONS":
165
77
  missions = get_missions()
166
78
  globals()["MISSIONS"] = missions
@@ -169,9 +81,6 @@ def __getattr__(name: str) -> list[Mission]:
169
81
 
170
82
 
171
83
  def make_game(num_cogs: int = 2, map_name: str = "training_facility_open_1.map") -> MettaGridConfig:
172
- """Create a default cogs vs clips game configuration."""
173
- mission = HarvestMission.model_copy(deep=True)
174
- mission.num_cogs = num_cogs
175
- env = mission.make_env()
176
- env.game.map_builder = get_map(map_name)
177
- return env
84
+ """Create a default CogsGuard game configuration."""
85
+ mission = make_cogsguard_mission(num_agents=num_cogs)
86
+ return mission.make_env()