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
@@ -2,15 +2,8 @@
2
2
  Difficulty Variants for CoGames Missions
3
3
 
4
4
  This module defines difficulty levels that can be applied to any mission to create
5
- varied challenges. Each difficulty level modifies:
6
- - max_uses (extractor depletion)
7
- - efficiency (resource output per use)
8
- - energy_regen (passive energy recovery)
9
-
10
- The goal is to force agents to:
11
- 1. Explore wider to find multiple extractors
12
- 2. Learn about efficiency/depletion through observation
13
- 3. Adapt strategies based on resource availability
5
+ varied challenges. Each difficulty level modifies mission-level parameters like
6
+ energy regen, move cost, and capacity limits.
14
7
  """
15
8
 
16
9
  from __future__ import annotations
@@ -21,17 +14,11 @@ from typing import override
21
14
  from pydantic import Field
22
15
 
23
16
  from cogames.cogs_vs_clips.mission import Mission, MissionVariant
24
- from mettagrid.config.mettagrid_config import AssemblerConfig, MettaGridConfig
17
+ from mettagrid.config.mettagrid_config import MettaGridConfig
25
18
 
26
19
  logger = logging.getLogger(__name__)
27
20
 
28
21
 
29
- # -----------------------------------------------------------------------------
30
- # Module constants
31
- # -----------------------------------------------------------------------------
32
-
33
- RESOURCE_KEYS = ("carbon", "oxygen", "germanium", "silicon")
34
-
35
22
  # Allow zero to persist for difficulties that force no passive regen
36
23
  ENERGY_REGEN_FLOOR = 0
37
24
 
@@ -47,249 +34,38 @@ class DifficultyLevel(MissionVariant):
47
34
  name: str = Field(description="Difficulty name (easy, medium, hard, brutal, etc.)")
48
35
  description: str = Field(description="What makes this difficulty challenging", default="")
49
36
 
50
- allow_agent_scaling: bool = Field(default=True, description="Whether agent-count scaling helpers should run")
51
-
52
- # Extractor max_uses multipliers (relative to mission baseline)
53
- carbon_max_uses_mult: float = Field(default=1.0)
54
- oxygen_max_uses_mult: float = Field(default=1.0)
55
- germanium_max_uses_mult: float = Field(default=1.0)
56
- silicon_max_uses_mult: float = Field(default=1.0)
57
-
58
- # Extractor efficiency multipliers (relative to mission baseline)
59
- carbon_eff_mult: float = Field(default=1.0)
60
- oxygen_eff_mult: float = Field(default=1.0)
61
- germanium_eff_mult: float = Field(default=1.0)
62
- silicon_eff_mult: float = Field(default=1.0)
63
- charger_eff_mult: float = Field(default=1.0)
64
-
65
37
  # Energy regen multiplier (relative to mission baseline)
66
38
  energy_regen_mult: float = Field(default=1.0)
67
39
 
68
40
  # Absolute overrides (if set, ignore multipliers)
69
- carbon_max_uses_override: int | None = Field(default=None)
70
- oxygen_max_uses_override: int | None = Field(default=None)
71
- germanium_max_uses_override: int | None = Field(default=None)
72
- silicon_max_uses_override: int | None = Field(default=None)
73
-
74
- carbon_eff_override: int | None = Field(default=None)
75
- oxygen_eff_override: int | None = Field(default=None)
76
- germanium_eff_override: int | None = Field(default=None)
77
- silicon_eff_override: int | None = Field(default=None)
78
- charger_eff_override: int | None = Field(default=None)
79
-
80
41
  energy_regen_override: int | None = Field(default=None)
81
42
  move_energy_cost_override: int | None = Field(default=None)
82
43
  energy_capacity_override: int | None = Field(default=None)
83
44
  cargo_capacity_override: int | None = Field(default=None)
84
45
  max_steps_override: int | None = Field(default=None)
85
46
 
86
- # Clipping configuration
87
- clip_period: int = Field(default=0, description="Approximate period of time between clips")
88
- clip_target: str | None = Field(
89
- default=None, description="Specific extractor to clip (carbon/oxygen/germanium/silicon/charger)"
90
- )
91
- clip_immune_extractor: str | None = Field(default=None, description="Extractor that stays immune to clipping")
92
-
93
47
  @override
94
48
  def modify_mission(self, mission: Mission):
95
- """Apply a difficulty level to a mission instance.
96
-
97
- Modifies the mission's extractor configs and energy_regen in place.
98
-
99
- Args:
100
- mission: Mission instance to modify
101
- difficulty: DifficultyLevel to apply
102
- """
103
- # Apply max_uses (override if set, else multiply), then enforce floor of 1 if baseline > 0
104
- # Note: GermaniumExtractorConfig doesn't have max_uses field (it's hardcoded to 1 in station_cfg)
105
- for res in RESOURCE_KEYS:
106
- extractor = getattr(mission, f"{res}_extractor")
107
- # Skip if extractor doesn't have max_uses attribute (e.g., GermaniumExtractorConfig)
108
- if not hasattr(extractor, "max_uses"):
109
- continue
110
- override_val = getattr(self, f"{res}_max_uses_override")
111
- mult_val = getattr(self, f"{res}_max_uses_mult")
112
- if override_val is not None:
113
- extractor.max_uses = override_val
114
- else:
115
- try:
116
- mu = int(extractor.max_uses)
117
- scaled = int(mu * mult_val)
118
- extractor.max_uses = max(1, scaled) if mu > 0 else scaled
119
- except Exception:
120
- # Best-effort; leave as-is on failure
121
- pass
122
-
123
- # Apply efficiency (override if set, else multiply)
124
- for res in RESOURCE_KEYS:
125
- extractor = getattr(mission, f"{res}_extractor")
126
- override_val = getattr(self, f"{res}_eff_override")
127
- mult_val = getattr(self, f"{res}_eff_mult")
128
- if override_val is not None:
129
- extractor.efficiency = override_val
130
- else:
131
- try:
132
- eff = int(extractor.efficiency)
133
- extractor.efficiency = int(eff * mult_val)
134
- except Exception:
135
- pass
136
-
137
- # Charger efficiency
138
- if self.charger_eff_override is not None:
139
- mission.charger.efficiency = self.charger_eff_override
140
- else:
141
- mission.charger.efficiency = int(mission.charger.efficiency * self.charger_eff_mult)
142
-
49
+ """Apply a difficulty level to a mission instance."""
143
50
  # Energy regen
144
51
  if self.energy_regen_override is not None:
145
- mission.energy_regen_amount = self.energy_regen_override
52
+ mission.cog.energy_regen = self.energy_regen_override
146
53
  else:
147
- mission.energy_regen_amount = max(0, int(mission.energy_regen_amount * self.energy_regen_mult))
54
+ mission.cog.energy_regen = max(0, int(mission.cog.energy_regen * self.energy_regen_mult))
148
55
 
149
56
  # Mission-level overrides
150
57
  if self.move_energy_cost_override is not None:
151
- mission.move_energy_cost = self.move_energy_cost_override
58
+ mission.cog.move_energy_cost = self.move_energy_cost_override
152
59
  if self.energy_capacity_override is not None:
153
- mission.energy_capacity = self.energy_capacity_override
60
+ mission.cog.energy_limit = self.energy_capacity_override
154
61
  if self.cargo_capacity_override is not None:
155
- mission.cargo_capacity = self.cargo_capacity_override
156
-
157
- # Set clip_period on mission
158
- if self.clip_period > 0:
159
- mission.clip_period = self.clip_period
160
-
161
- # Apply clipping configuration
162
- clip_target = self.clip_target
163
-
164
- # Set the specific station to start clipped
165
- if clip_target == "carbon":
166
- mission.carbon_extractor.start_clipped = True
167
- logger.info("Set carbon_extractor.start_clipped = True")
168
- elif clip_target == "oxygen":
169
- mission.oxygen_extractor.start_clipped = True
170
- logger.info(
171
- f"Set oxygen_extractor.start_clipped = True (current value: {mission.oxygen_extractor.start_clipped})"
172
- )
173
- elif clip_target == "germanium":
174
- mission.germanium_extractor.start_clipped = True
175
- logger.info("Set germanium_extractor.start_clipped = True")
176
- elif clip_target == "silicon":
177
- mission.silicon_extractor.start_clipped = True
178
- logger.info("Set silicon_extractor.start_clipped = True")
179
- elif clip_target == "charger":
180
- mission.charger.start_clipped = True
181
- logger.info("Set charger.start_clipped = True")
62
+ mission.cog.cargo_limit = self.cargo_capacity_override
182
63
 
183
64
  @override
184
65
  def modify_env(self, mission: Mission, env: MettaGridConfig):
185
66
  if self.max_steps_override is not None:
186
67
  env.game.max_steps = self.max_steps_override
187
68
 
188
- # Apply clipping first (before agent scaling)
189
- self._apply_clipping(env)
190
-
191
- if not self.allow_agent_scaling:
192
- return
193
-
194
- # Post-build agent-aware scaling: scale extractor max_uses roughly with num_agents
195
- num_agents = env.game.num_agents
196
-
197
- # Scale extractor resources for multi-agent scenarios
198
- for res in RESOURCE_KEYS:
199
- key = f"{res}_extractor"
200
- obj = env.game.objects.get(key)
201
- if not isinstance(obj, AssemblerConfig):
202
- continue
203
-
204
- # Scale max_uses by agent count (leave unlimited=0 as-is)
205
- if obj.max_uses > 0 and num_agents > 1:
206
- obj.max_uses = obj.max_uses * num_agents
207
-
208
- # Energy regen floor: if nonzero, keep at least 1
209
- default_regen = env.game.agent.inventory.regen_amounts.get("default", {})
210
- current_regen = default_regen.get("energy", 1)
211
- if current_regen > 0:
212
- if "default" not in env.game.agent.inventory.regen_amounts:
213
- env.game.agent.inventory.regen_amounts["default"] = {}
214
- env.game.agent.inventory.regen_amounts["default"]["energy"] = max(ENERGY_REGEN_FLOOR, current_regen)
215
-
216
- def _apply_clipping(self, cfg: MettaGridConfig) -> None:
217
- target = self.clip_target
218
-
219
- # Determine gear and resource mapping for unclipping
220
- gear_by_target: dict[str, tuple[str, str]] = {
221
- "carbon": ("modulator", "oxygen"),
222
- "oxygen": ("decoder", "carbon"),
223
- "germanium": ("resonator", "silicon"),
224
- "silicon": ("scrambler", "germanium"),
225
- }
226
-
227
- if target not in gear_by_target:
228
- return
229
-
230
- required_gear, resource_for_gear = gear_by_target[target]
231
-
232
- def _filter_unclip() -> None:
233
- """Filter unclipping protocols to only the required gear."""
234
- if cfg.game.clipper is None:
235
- logger.warning("_filter_unclip: clipper is None, skipping")
236
- return
237
-
238
- original_count = len(cfg.game.clipper.unclipping_protocols)
239
- cfg.game.clipper.unclipping_protocols = [
240
- r for r in cfg.game.clipper.unclipping_protocols if r.input_resources == {required_gear: 1}
241
- ]
242
- new_count = len(cfg.game.clipper.unclipping_protocols)
243
- logger.info(
244
- f"_filter_unclip: filtered unclipping protocols from {original_count} to {new_count} "
245
- f"(keeping {required_gear})"
246
- )
247
-
248
- def _add_gear_protocol() -> None:
249
- """Add generic ['gear'] protocol to assembler for this specific clipping variant.
250
-
251
- C++ only allows ONE protocol per unique vibe list, so we add just the one needed.
252
- """
253
- from mettagrid.config.mettagrid_config import AssemblerConfig, ProtocolConfig
254
-
255
- asm = cfg.game.objects.get("assembler")
256
- if asm is None or not isinstance(asm, AssemblerConfig):
257
- return
258
-
259
- # Check if ['gear'] protocol already exists
260
- if any(p.vibes == ["gear"] for p in asm.protocols):
261
- return # Already added
262
-
263
- # Add the ONE generic gear protocol for this variant
264
- protocol = ProtocolConfig(
265
- vibes=["gear"], input_resources={resource_for_gear: 1}, output_resources={required_gear: 1}
266
- )
267
- asm.protocols.append(protocol)
268
-
269
- def _ensure_gear_resource_immune() -> None:
270
- """Make the extractor for the gear resource immune to clipping."""
271
- immune_extractor_name = self.clip_immune_extractor or f"{resource_for_gear}_extractor"
272
- obj = cfg.game.objects.get(immune_extractor_name)
273
- if not isinstance(obj, AssemblerConfig):
274
- return
275
- obj.clip_immune = True
276
- obj.start_clipped = False
277
-
278
- def _ensure_critical_stations_immune() -> None:
279
- """Make charger, assembler, and chest immune to clipping."""
280
- for station_name in ["charger", "assembler", "chest"]:
281
- obj = cfg.game.objects.get(station_name)
282
- if not isinstance(obj, AssemblerConfig):
283
- continue
284
- obj.clip_immune = True
285
- obj.start_clipped = False
286
-
287
- # Apply clipping modifiers
288
- _filter_unclip()
289
- _add_gear_protocol()
290
- _ensure_gear_resource_immune()
291
- _ensure_critical_stations_immune()
292
-
293
69
 
294
70
  # =============================================================================
295
71
  # Standard Difficulty Levels
@@ -302,105 +78,29 @@ STANDARD = DifficultyLevel(
302
78
 
303
79
  HARD = DifficultyLevel(
304
80
  name="hard",
305
- description="Tight extractor budgets and minimal passive regen",
306
- carbon_max_uses_override=4,
307
- oxygen_max_uses_override=4,
308
- germanium_max_uses_override=6,
309
- silicon_max_uses_override=3,
310
- carbon_eff_override=85,
311
- oxygen_eff_override=65,
312
- germanium_eff_override=75,
313
- silicon_eff_override=70,
314
- charger_eff_override=100,
81
+ description="Minimal passive regen and higher move cost",
315
82
  energy_regen_override=1, # Minimal regen prevents deadlock
316
83
  move_energy_cost_override=2,
317
- allow_agent_scaling=False,
318
84
  )
319
85
 
320
86
  SINGLE_USE = DifficultyLevel(
321
87
  name="single_use",
322
- description="Every extractor can be used exactly once - no second chances",
323
- carbon_max_uses_override=1,
324
- oxygen_max_uses_override=1,
325
- germanium_max_uses_override=1,
326
- silicon_max_uses_override=1,
327
- charger_eff_override=120,
88
+ description="Minimal regen - no second chances",
328
89
  energy_regen_override=1,
329
- allow_agent_scaling=False,
330
90
  )
331
91
 
332
92
  SPEED_RUN = DifficultyLevel(
333
93
  name="speed_run",
334
- description="Short clock, cheap movement, efficient extraction",
335
- carbon_max_uses_override=6,
336
- oxygen_max_uses_override=6,
337
- germanium_max_uses_override=6,
338
- silicon_max_uses_override=6,
339
- carbon_eff_override=160,
340
- oxygen_eff_override=160,
341
- germanium_eff_override=160,
342
- silicon_eff_override=160,
343
- charger_eff_override=160,
94
+ description="Short clock, cheap movement",
344
95
  energy_regen_override=2,
345
96
  move_energy_cost_override=1,
346
97
  max_steps_override=600,
347
- allow_agent_scaling=True,
348
98
  )
349
99
 
350
100
  ENERGY_CRISIS = DifficultyLevel(
351
101
  name="energy_crisis",
352
- description="Minimal passive regen and weak chargers - plan every move",
353
- charger_eff_override=50,
102
+ description="Minimal passive regen - plan every move",
354
103
  energy_regen_override=1, # Minimal regen prevents deadlock
355
- allow_agent_scaling=False,
356
- )
357
-
358
- # =============================================================================
359
- # Clipping Difficulty Variants
360
- # =============================================================================
361
-
362
- CLIPPED_OXYGEN = DifficultyLevel(
363
- name="clipped_oxygen",
364
- description="Oxygen extractor starts clipped - craft decoder from carbon to unclip",
365
- clip_period=0,
366
- clip_target="oxygen",
367
- clip_immune_extractor="carbon_extractor",
368
- allow_agent_scaling=False,
369
- )
370
-
371
- CLIPPED_CARBON = DifficultyLevel(
372
- name="clipped_carbon",
373
- description="Carbon extractor starts clipped - craft modulator from oxygen to unclip",
374
- clip_period=0,
375
- clip_target="carbon",
376
- clip_immune_extractor="oxygen_extractor",
377
- allow_agent_scaling=False,
378
- )
379
-
380
- CLIPPED_GERMANIUM = DifficultyLevel(
381
- name="clipped_germanium",
382
- description="Germanium extractor starts clipped - craft resonator from silicon to unclip",
383
- clip_period=0,
384
- clip_target="germanium",
385
- clip_immune_extractor="silicon_extractor",
386
- allow_agent_scaling=False,
387
- )
388
-
389
- CLIPPED_SILICON = DifficultyLevel(
390
- name="clipped_silicon",
391
- description="Silicon extractor starts clipped - craft scrambler from germanium to unclip",
392
- clip_period=0,
393
- clip_target="silicon",
394
- clip_immune_extractor="germanium_extractor",
395
- allow_agent_scaling=False,
396
- )
397
-
398
- CLIPPING_CHAOS = DifficultyLevel(
399
- name="clipping_chaos",
400
- description="Random extractors clip over time - must craft unclip items reactively",
401
- clip_period=7,
402
- clip_target=None,
403
- allow_agent_scaling=False,
404
104
  )
405
105
 
406
106
  # Export variants for use with --variant CLI flag.
@@ -411,11 +111,6 @@ DIFFICULTY_VARIANTS: list[DifficultyLevel] = [
411
111
  SINGLE_USE,
412
112
  SPEED_RUN,
413
113
  ENERGY_CRISIS,
414
- CLIPPED_OXYGEN,
415
- CLIPPED_CARBON,
416
- CLIPPED_GERMANIUM,
417
- CLIPPED_SILICON,
418
- CLIPPING_CHAOS,
419
114
  ]
420
115
 
421
116
 
@@ -430,14 +125,6 @@ def list_difficulties() -> None:
430
125
  print("=" * 80)
431
126
  for diff in DIFFICULTY_VARIANTS:
432
127
  print(f"\n{diff.name.upper()}: {diff.description}")
433
- print(
434
- f" Max uses mult: C={diff.carbon_max_uses_mult}, O={diff.oxygen_max_uses_mult}, "
435
- f"G={diff.germanium_max_uses_mult}, S={diff.silicon_max_uses_mult}"
436
- )
437
- print(
438
- f" Efficiency mult: C={diff.carbon_eff_mult}, O={diff.oxygen_eff_mult}, "
439
- f"G={diff.germanium_eff_mult}, S={diff.silicon_eff_mult}"
440
- )
441
128
  print(f" Energy regen mult: {diff.energy_regen_mult}")
442
129
 
443
130
 
@@ -9,15 +9,9 @@ from cogames.cogs_vs_clips.variants import (
9
9
  DarkSideVariant,
10
10
  DistantResourcesVariant,
11
11
  EmptyBaseVariant,
12
- ExtractorHeartTuneVariant,
13
- HeartChorusVariant,
14
- LonelyHeartVariant,
15
12
  PackRatVariant,
16
13
  QuadrantBuildingsVariant,
17
- ResourceBottleneckVariant,
18
14
  SingleResourceUniformVariant,
19
- SingleUseSwarmVariant,
20
- VibeCheckMin2Variant,
21
15
  )
22
16
  from mettagrid.mapgen.mapgen import MapGen
23
17
 
@@ -46,34 +40,31 @@ LARGE_HELLO_WORLD = Site(
46
40
  min_cogs=1,
47
41
  max_cogs=20,
48
42
  )
49
- # Resource Bottleneck evals (Different resources are the limiting reagents; agents must prioritize correct resource.)
43
+
44
+ # Resource Bottleneck evals
50
45
  OxygenBottleneck = Mission(
51
46
  name="oxygen_bottleneck",
52
47
  description="Oxygen is the limiting resource; agents must prioritize oxygen over other resources.",
53
48
  site=HELLO_WORLD,
54
49
  variants=[
55
50
  EmptyBaseVariant(missing=["oxygen_extractor"]),
56
- ExtractorHeartTuneVariant(hearts=10),
57
- ResourceBottleneckVariant(resource="oxygen"),
58
51
  SingleResourceUniformVariant(building_name="oxygen_extractor"),
59
52
  PackRatVariant(),
60
53
  ],
61
54
  )
62
55
 
63
- # Energy Starved evals (Low energy regen and weak chargers; requires careful charging and routing.)
56
+ # Energy Starved evals
64
57
  EnergyStarved = Mission(
65
58
  name="energy_starved",
66
59
  description="Energy is the limiting resource; agents must prioritize energy over other resources.",
67
60
  site=HELLO_WORLD,
68
61
  variants=[
69
62
  EmptyBaseVariant(),
70
- ResourceBottleneckVariant(resource="energy"),
71
63
  DarkSideVariant(),
72
64
  ],
73
65
  )
74
66
 
75
- # Collect Distant Resources evals (Resources scattered far from base; heavy routing coordination.)
76
-
67
+ # Collect Distant Resources evals
77
68
  DistantResources = Mission(
78
69
  name="distant_resources",
79
70
  description="Resources scattered far from base; heavy routing coordination.",
@@ -84,8 +75,7 @@ DistantResources = Mission(
84
75
  ],
85
76
  )
86
77
 
87
- # Divide and Conquer evals (Resources split by regions; specialize per resource and reconvene at base.)
88
-
78
+ # Divide and Conquer evals
89
79
  QuadrantBuildings = Mission(
90
80
  name="quadrant_buildings",
91
81
  description="Place buildings in the four quadrants of the map.",
@@ -96,39 +86,11 @@ QuadrantBuildings = Mission(
96
86
  ],
97
87
  )
98
88
 
99
- # Single Use Swarm evals (Everything is single use, so agents must fan out and reconverge with needed resources.)
100
-
101
- SingleUseSwarm = Mission(
102
- name="single_use_swarm",
103
- description="Everything is single use, so agents must fan out and reconverge with needed resources.",
104
- site=HELLO_WORLD,
105
- variants=[
106
- EmptyBaseVariant(),
107
- SingleUseSwarmVariant(),
108
- PackRatVariant(),
109
- ],
110
- )
111
-
112
- # Vibe Check evals (Agents must check their vibe, either binary or full, and then coordinate others for assembly.)
113
-
114
- VibeCheck = Mission(
115
- name="vibe_check",
116
- description="Agents must check their vibe, either binary or full, and then coordinate others for assembly.",
117
- site=HELLO_WORLD,
118
- variants=[
119
- EmptyBaseVariant(),
120
- HeartChorusVariant(),
121
- VibeCheckMin2Variant(),
122
- ],
123
- )
124
-
125
89
  EasyHeartsMission = Mission(
126
90
  name="easy_hearts",
127
91
  description="Simplified heart crafting with generous caps and extractor base.",
128
92
  site=HELLO_WORLD,
129
93
  variants=[
130
- LonelyHeartVariant(),
131
- HeartChorusVariant(),
132
94
  PackRatVariant(),
133
95
  ],
134
96
  )
@@ -139,7 +101,5 @@ EVAL_MISSIONS: list[Mission] = [
139
101
  EnergyStarved,
140
102
  DistantResources,
141
103
  QuadrantBuildings,
142
- SingleUseSwarm,
143
- VibeCheck,
144
104
  EasyHeartsMission,
145
105
  ]