cogames-agents 0.0.0.7__cp312-cp312-macosx_11_0_arm64.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 (128) hide show
  1. cogames_agents/__init__.py +0 -0
  2. cogames_agents/evals/__init__.py +5 -0
  3. cogames_agents/evals/planky_evals.py +415 -0
  4. cogames_agents/policy/__init__.py +0 -0
  5. cogames_agents/policy/evolution/__init__.py +0 -0
  6. cogames_agents/policy/evolution/cogsguard/__init__.py +0 -0
  7. cogames_agents/policy/evolution/cogsguard/evolution.py +695 -0
  8. cogames_agents/policy/evolution/cogsguard/evolutionary_coordinator.py +540 -0
  9. cogames_agents/policy/nim_agents/__init__.py +20 -0
  10. cogames_agents/policy/nim_agents/agents.py +98 -0
  11. cogames_agents/policy/nim_agents/bindings/generated/libnim_agents.dylib +0 -0
  12. cogames_agents/policy/nim_agents/bindings/generated/nim_agents.py +215 -0
  13. cogames_agents/policy/nim_agents/cogsguard_agents.nim +555 -0
  14. cogames_agents/policy/nim_agents/cogsguard_align_all_agents.nim +569 -0
  15. cogames_agents/policy/nim_agents/common.nim +1054 -0
  16. cogames_agents/policy/nim_agents/install.sh +1 -0
  17. cogames_agents/policy/nim_agents/ladybug_agent.nim +954 -0
  18. cogames_agents/policy/nim_agents/nim_agents.nim +68 -0
  19. cogames_agents/policy/nim_agents/nim_agents.nims +14 -0
  20. cogames_agents/policy/nim_agents/nimby.lock +3 -0
  21. cogames_agents/policy/nim_agents/racecar_agents.nim +844 -0
  22. cogames_agents/policy/nim_agents/random_agents.nim +68 -0
  23. cogames_agents/policy/nim_agents/test_agents.py +53 -0
  24. cogames_agents/policy/nim_agents/thinky_agents.nim +677 -0
  25. cogames_agents/policy/nim_agents/thinky_eval.py +230 -0
  26. cogames_agents/policy/scripted_agent/README.md +360 -0
  27. cogames_agents/policy/scripted_agent/__init__.py +0 -0
  28. cogames_agents/policy/scripted_agent/baseline_agent.py +1031 -0
  29. cogames_agents/policy/scripted_agent/cogas/__init__.py +5 -0
  30. cogames_agents/policy/scripted_agent/cogas/context.py +68 -0
  31. cogames_agents/policy/scripted_agent/cogas/entity_map.py +152 -0
  32. cogames_agents/policy/scripted_agent/cogas/goal.py +115 -0
  33. cogames_agents/policy/scripted_agent/cogas/goals/__init__.py +27 -0
  34. cogames_agents/policy/scripted_agent/cogas/goals/aligner.py +160 -0
  35. cogames_agents/policy/scripted_agent/cogas/goals/gear.py +197 -0
  36. cogames_agents/policy/scripted_agent/cogas/goals/miner.py +441 -0
  37. cogames_agents/policy/scripted_agent/cogas/goals/scout.py +40 -0
  38. cogames_agents/policy/scripted_agent/cogas/goals/scrambler.py +174 -0
  39. cogames_agents/policy/scripted_agent/cogas/goals/shared.py +160 -0
  40. cogames_agents/policy/scripted_agent/cogas/goals/stem.py +60 -0
  41. cogames_agents/policy/scripted_agent/cogas/goals/survive.py +100 -0
  42. cogames_agents/policy/scripted_agent/cogas/navigator.py +401 -0
  43. cogames_agents/policy/scripted_agent/cogas/obs_parser.py +238 -0
  44. cogames_agents/policy/scripted_agent/cogas/policy.py +525 -0
  45. cogames_agents/policy/scripted_agent/cogas/trace.py +69 -0
  46. cogames_agents/policy/scripted_agent/cogsguard/CLAUDE.md +517 -0
  47. cogames_agents/policy/scripted_agent/cogsguard/README.md +252 -0
  48. cogames_agents/policy/scripted_agent/cogsguard/__init__.py +74 -0
  49. cogames_agents/policy/scripted_agent/cogsguard/aligned_junction_held_investigation.md +152 -0
  50. cogames_agents/policy/scripted_agent/cogsguard/aligner.py +333 -0
  51. cogames_agents/policy/scripted_agent/cogsguard/behavior_hooks.py +44 -0
  52. cogames_agents/policy/scripted_agent/cogsguard/control_agent.py +323 -0
  53. cogames_agents/policy/scripted_agent/cogsguard/debug_agent.py +533 -0
  54. cogames_agents/policy/scripted_agent/cogsguard/miner.py +589 -0
  55. cogames_agents/policy/scripted_agent/cogsguard/options.py +67 -0
  56. cogames_agents/policy/scripted_agent/cogsguard/parity_metrics.py +36 -0
  57. cogames_agents/policy/scripted_agent/cogsguard/policy.py +1967 -0
  58. cogames_agents/policy/scripted_agent/cogsguard/prereq_trace.py +33 -0
  59. cogames_agents/policy/scripted_agent/cogsguard/role_trace.py +50 -0
  60. cogames_agents/policy/scripted_agent/cogsguard/roles.py +31 -0
  61. cogames_agents/policy/scripted_agent/cogsguard/rollout_trace.py +40 -0
  62. cogames_agents/policy/scripted_agent/cogsguard/scout.py +69 -0
  63. cogames_agents/policy/scripted_agent/cogsguard/scrambler.py +350 -0
  64. cogames_agents/policy/scripted_agent/cogsguard/targeted_agent.py +418 -0
  65. cogames_agents/policy/scripted_agent/cogsguard/teacher.py +224 -0
  66. cogames_agents/policy/scripted_agent/cogsguard/types.py +381 -0
  67. cogames_agents/policy/scripted_agent/cogsguard/v2_agent.py +49 -0
  68. cogames_agents/policy/scripted_agent/common/__init__.py +0 -0
  69. cogames_agents/policy/scripted_agent/common/geometry.py +24 -0
  70. cogames_agents/policy/scripted_agent/common/roles.py +34 -0
  71. cogames_agents/policy/scripted_agent/common/tag_utils.py +48 -0
  72. cogames_agents/policy/scripted_agent/demo_policy.py +242 -0
  73. cogames_agents/policy/scripted_agent/pathfinding.py +126 -0
  74. cogames_agents/policy/scripted_agent/pinky/DESIGN.md +317 -0
  75. cogames_agents/policy/scripted_agent/pinky/__init__.py +5 -0
  76. cogames_agents/policy/scripted_agent/pinky/behaviors/__init__.py +17 -0
  77. cogames_agents/policy/scripted_agent/pinky/behaviors/aligner.py +400 -0
  78. cogames_agents/policy/scripted_agent/pinky/behaviors/base.py +119 -0
  79. cogames_agents/policy/scripted_agent/pinky/behaviors/miner.py +632 -0
  80. cogames_agents/policy/scripted_agent/pinky/behaviors/scout.py +138 -0
  81. cogames_agents/policy/scripted_agent/pinky/behaviors/scrambler.py +433 -0
  82. cogames_agents/policy/scripted_agent/pinky/policy.py +570 -0
  83. cogames_agents/policy/scripted_agent/pinky/services/__init__.py +7 -0
  84. cogames_agents/policy/scripted_agent/pinky/services/map_tracker.py +808 -0
  85. cogames_agents/policy/scripted_agent/pinky/services/navigator.py +864 -0
  86. cogames_agents/policy/scripted_agent/pinky/services/safety.py +189 -0
  87. cogames_agents/policy/scripted_agent/pinky/state.py +299 -0
  88. cogames_agents/policy/scripted_agent/pinky/types.py +138 -0
  89. cogames_agents/policy/scripted_agent/planky/CLAUDE.md +124 -0
  90. cogames_agents/policy/scripted_agent/planky/IMPROVEMENTS.md +160 -0
  91. cogames_agents/policy/scripted_agent/planky/NOTES.md +153 -0
  92. cogames_agents/policy/scripted_agent/planky/PLAN.md +254 -0
  93. cogames_agents/policy/scripted_agent/planky/README.md +214 -0
  94. cogames_agents/policy/scripted_agent/planky/STRATEGY.md +100 -0
  95. cogames_agents/policy/scripted_agent/planky/__init__.py +5 -0
  96. cogames_agents/policy/scripted_agent/planky/context.py +68 -0
  97. cogames_agents/policy/scripted_agent/planky/entity_map.py +152 -0
  98. cogames_agents/policy/scripted_agent/planky/goal.py +107 -0
  99. cogames_agents/policy/scripted_agent/planky/goals/__init__.py +27 -0
  100. cogames_agents/policy/scripted_agent/planky/goals/aligner.py +168 -0
  101. cogames_agents/policy/scripted_agent/planky/goals/gear.py +179 -0
  102. cogames_agents/policy/scripted_agent/planky/goals/miner.py +416 -0
  103. cogames_agents/policy/scripted_agent/planky/goals/scout.py +40 -0
  104. cogames_agents/policy/scripted_agent/planky/goals/scrambler.py +174 -0
  105. cogames_agents/policy/scripted_agent/planky/goals/shared.py +160 -0
  106. cogames_agents/policy/scripted_agent/planky/goals/stem.py +49 -0
  107. cogames_agents/policy/scripted_agent/planky/goals/survive.py +96 -0
  108. cogames_agents/policy/scripted_agent/planky/navigator.py +388 -0
  109. cogames_agents/policy/scripted_agent/planky/obs_parser.py +238 -0
  110. cogames_agents/policy/scripted_agent/planky/policy.py +485 -0
  111. cogames_agents/policy/scripted_agent/planky/tests/__init__.py +0 -0
  112. cogames_agents/policy/scripted_agent/planky/tests/conftest.py +66 -0
  113. cogames_agents/policy/scripted_agent/planky/tests/helpers.py +152 -0
  114. cogames_agents/policy/scripted_agent/planky/tests/test_aligner.py +24 -0
  115. cogames_agents/policy/scripted_agent/planky/tests/test_miner.py +30 -0
  116. cogames_agents/policy/scripted_agent/planky/tests/test_scout.py +15 -0
  117. cogames_agents/policy/scripted_agent/planky/tests/test_scrambler.py +29 -0
  118. cogames_agents/policy/scripted_agent/planky/tests/test_stem.py +36 -0
  119. cogames_agents/policy/scripted_agent/planky/trace.py +69 -0
  120. cogames_agents/policy/scripted_agent/types.py +239 -0
  121. cogames_agents/policy/scripted_agent/unclipping_agent.py +461 -0
  122. cogames_agents/policy/scripted_agent/utils.py +381 -0
  123. cogames_agents/policy/scripted_registry.py +80 -0
  124. cogames_agents/py.typed +0 -0
  125. cogames_agents-0.0.0.7.dist-info/METADATA +98 -0
  126. cogames_agents-0.0.0.7.dist-info/RECORD +128 -0
  127. cogames_agents-0.0.0.7.dist-info/WHEEL +6 -0
  128. cogames_agents-0.0.0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,238 @@
1
+ """Observation parser for Planky policy.
2
+
3
+ Converts raw observation tokens into StateSnapshot and visible entities.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import TYPE_CHECKING
9
+
10
+ from .context import StateSnapshot
11
+ from .entity_map import Entity
12
+
13
+ if TYPE_CHECKING:
14
+ from mettagrid.policy.policy_env_interface import PolicyEnvInterface
15
+ from mettagrid.simulator.interface import AgentObservation
16
+
17
+
18
+ class ObsParser:
19
+ """Parses observation tokens into state snapshot and visible entities."""
20
+
21
+ def __init__(self, policy_env_info: PolicyEnvInterface) -> None:
22
+ self._obs_hr = policy_env_info.obs_height // 2
23
+ self._obs_wr = policy_env_info.obs_width // 2
24
+ self._tag_names = policy_env_info.tag_id_to_name
25
+
26
+ # Derive vibe names from action names
27
+ self._vibe_names: list[str] = []
28
+ for action_name in policy_env_info.action_names:
29
+ if action_name.startswith("change_vibe_"):
30
+ self._vibe_names.append(action_name[len("change_vibe_") :])
31
+
32
+ # Collective name mapping
33
+ self._collective_names = ["clips", "cogs"] # Alphabetical
34
+ self._cogs_collective_id = 1 # "cogs" is index 1 alphabetically
35
+ self._clips_collective_id = 0 # "clips" is index 0
36
+
37
+ def parse(
38
+ self,
39
+ obs: AgentObservation,
40
+ step: int,
41
+ spawn_pos: tuple[int, int],
42
+ ) -> tuple[StateSnapshot, dict[tuple[int, int], Entity]]:
43
+ """Parse observation into state snapshot and visible entities.
44
+
45
+ Args:
46
+ obs: Raw observation
47
+ step: Current tick
48
+ spawn_pos: Agent's spawn position for offset calculation
49
+
50
+ Returns:
51
+ (state_snapshot, visible_entities_dict)
52
+ """
53
+ state = StateSnapshot()
54
+
55
+ # Read center cell for inventory/vibe and local position
56
+ inv: dict[str, int] = {}
57
+ vibe_id = 0
58
+ # Local position tokens: lp:east/west for col offset, lp:north/south for row offset
59
+ lp_col_offset = 0 # east is positive, west is negative
60
+ lp_row_offset = 0 # south is positive, north is negative
61
+ has_position = False
62
+
63
+ center_r, center_c = self._obs_hr, self._obs_wr
64
+
65
+ for tok in obs.tokens:
66
+ if tok.row() == center_r and tok.col() == center_c:
67
+ feature_name = tok.feature.name
68
+ if feature_name.startswith("inv:"):
69
+ resource_name = feature_name[4:]
70
+ # Handle multi-token encoding
71
+ if ":p" in resource_name:
72
+ base_name, power_str = resource_name.rsplit(":p", 1)
73
+ power = int(power_str)
74
+ current = inv.get(base_name, 0)
75
+ inv[base_name] = current + tok.value * (256**power)
76
+ else:
77
+ current = inv.get(resource_name, 0)
78
+ inv[resource_name] = current + tok.value
79
+ elif feature_name == "vibe":
80
+ vibe_id = tok.value
81
+ # Local position tokens from local_position observation feature
82
+ elif feature_name == "lp:east":
83
+ lp_col_offset = tok.value
84
+ has_position = True
85
+ elif feature_name == "lp:west":
86
+ lp_col_offset = -tok.value
87
+ has_position = True
88
+ elif feature_name == "lp:south":
89
+ lp_row_offset = tok.value
90
+ has_position = True
91
+ elif feature_name == "lp:north":
92
+ lp_row_offset = -tok.value
93
+ has_position = True
94
+
95
+ # Build state - lp: tokens give offset from spawn
96
+ if has_position:
97
+ state.position = (spawn_pos[0] + lp_row_offset, spawn_pos[1] + lp_col_offset)
98
+ else:
99
+ state.position = spawn_pos
100
+
101
+ state.hp = inv.get("hp", 100)
102
+ state.energy = inv.get("energy", 100)
103
+ state.carbon = inv.get("carbon", 0)
104
+ state.oxygen = inv.get("oxygen", 0)
105
+ state.germanium = inv.get("germanium", 0)
106
+ state.silicon = inv.get("silicon", 0)
107
+ state.heart = inv.get("heart", 0)
108
+ state.influence = inv.get("influence", 0)
109
+ state.miner_gear = inv.get("miner", 0) > 0
110
+ state.scout_gear = inv.get("scout", 0) > 0
111
+ state.aligner_gear = inv.get("aligner", 0) > 0
112
+ state.scrambler_gear = inv.get("scrambler", 0) > 0
113
+ state.vibe = self._get_vibe_name(vibe_id)
114
+
115
+ # Read collective inventory from the inv dict.
116
+ # Collective tokens appear as "inv:collective:<resource>" features on the center cell,
117
+ # parsed above into keys like "collective:carbon", "collective:oxygen", etc.
118
+ state.collective_carbon = inv.get("collective:carbon", 0)
119
+ state.collective_oxygen = inv.get("collective:oxygen", 0)
120
+ state.collective_germanium = inv.get("collective:germanium", 0)
121
+ state.collective_silicon = inv.get("collective:silicon", 0)
122
+ state.collective_heart = inv.get("collective:heart", 0)
123
+ state.collective_influence = inv.get("collective:influence", 0)
124
+
125
+ # Parse visible entities
126
+ visible_entities: dict[tuple[int, int], Entity] = {}
127
+ position_features: dict[tuple[int, int], dict] = {}
128
+
129
+ for tok in obs.tokens:
130
+ obs_r, obs_c = tok.row(), tok.col()
131
+ # Skip center cell
132
+ if obs_r == center_r and obs_c == center_c:
133
+ continue
134
+
135
+ world_r = obs_r - self._obs_hr + state.position[0]
136
+ world_c = obs_c - self._obs_wr + state.position[1]
137
+ world_pos = (world_r, world_c)
138
+
139
+ if world_pos not in position_features:
140
+ position_features[world_pos] = {"tags": [], "props": {}}
141
+
142
+ feature_name = tok.feature.name
143
+ if feature_name == "tag":
144
+ position_features[world_pos]["tags"].append(tok.value)
145
+ elif feature_name in ("cooldown_remaining", "clipped", "remaining_uses", "collective"):
146
+ position_features[world_pos]["props"][feature_name] = tok.value
147
+ elif feature_name.startswith("inv:"):
148
+ inv_dict = position_features[world_pos].setdefault("inventory", {})
149
+ suffix = feature_name[4:]
150
+ if ":p" in suffix:
151
+ base_name, power_str = suffix.rsplit(":p", 1)
152
+ power = int(power_str)
153
+ current = inv_dict.get(base_name, 0)
154
+ inv_dict[base_name] = current + tok.value * (256**power)
155
+ else:
156
+ current = inv_dict.get(suffix, 0)
157
+ inv_dict[suffix] = current + tok.value
158
+
159
+ # Convert to entities
160
+ for world_pos, features in position_features.items():
161
+ tags = features.get("tags", [])
162
+ if not tags:
163
+ continue
164
+
165
+ obj_name = self._resolve_object_name(tags)
166
+ if obj_name == "unknown":
167
+ continue
168
+
169
+ props = dict(features.get("props", {}))
170
+ inv_data = features.get("inventory")
171
+
172
+ # Alignment from collective ID
173
+ collective_id = props.pop("collective", None)
174
+ if collective_id is not None:
175
+ props["collective_id"] = collective_id
176
+ alignment = self._derive_alignment(obj_name, props.get("clipped", 0), collective_id)
177
+ if alignment:
178
+ props["alignment"] = alignment
179
+
180
+ # Remaining uses
181
+ if "remaining_uses" not in props:
182
+ props["remaining_uses"] = 999
183
+
184
+ # Inventory amount for extractors
185
+ if inv_data:
186
+ props["inventory_amount"] = sum(inv_data.values())
187
+ props["has_inventory"] = True
188
+ else:
189
+ props.setdefault("inventory_amount", -1)
190
+
191
+ visible_entities[world_pos] = Entity(
192
+ type=obj_name,
193
+ properties=props,
194
+ last_seen=step,
195
+ )
196
+
197
+ return state, visible_entities
198
+
199
+ def _resolve_object_name(self, tag_ids: list[int]) -> str:
200
+ """Resolve tag IDs to an object name."""
201
+ resolved = [self._tag_names.get(tid, "") for tid in tag_ids]
202
+
203
+ # Priority: type:* tags
204
+ for tag in resolved:
205
+ if tag.startswith("type:"):
206
+ return tag[5:]
207
+
208
+ # Non-collective tags
209
+ for tag in resolved:
210
+ if tag and not tag.startswith("collective:"):
211
+ return tag
212
+
213
+ return "unknown"
214
+
215
+ def _get_vibe_name(self, vibe_id: int) -> str:
216
+ if 0 <= vibe_id < len(self._vibe_names):
217
+ return self._vibe_names[vibe_id]
218
+ return "default"
219
+
220
+ def _derive_alignment(self, obj_name: str, clipped: int, collective_id: int | None) -> str | None:
221
+ if collective_id is not None:
222
+ if collective_id == self._cogs_collective_id:
223
+ return "cogs"
224
+ elif collective_id == self._clips_collective_id:
225
+ return "clips"
226
+ if "cogs" in obj_name:
227
+ return "cogs"
228
+ if "clips" in obj_name or clipped > 0:
229
+ return "clips"
230
+ return None
231
+
232
+ @property
233
+ def obs_half_height(self) -> int:
234
+ return self._obs_hr
235
+
236
+ @property
237
+ def obs_half_width(self) -> int:
238
+ return self._obs_wr