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.
- cogames/cli/client.py +60 -6
- cogames/cli/docsync/__init__.py +0 -0
- cogames/cli/docsync/_nb_md_directive_processing.py +180 -0
- cogames/cli/docsync/_nb_md_sync.py +103 -0
- cogames/cli/docsync/_nb_py_sync.py +122 -0
- cogames/cli/docsync/_three_way_sync.py +115 -0
- cogames/cli/docsync/_utils.py +76 -0
- cogames/cli/docsync/docsync.py +156 -0
- cogames/cli/leaderboard.py +112 -28
- cogames/cli/mission.py +64 -53
- cogames/cli/policy.py +46 -10
- cogames/cli/submit.py +268 -67
- cogames/cogs_vs_clips/cog.py +79 -0
- cogames/cogs_vs_clips/cogs_vs_clips_mapgen.md +19 -16
- cogames/cogs_vs_clips/cogsguard_reward_variants.py +153 -0
- cogames/cogs_vs_clips/cogsguard_tutorial.py +56 -0
- cogames/cogs_vs_clips/evals/README.md +10 -16
- cogames/cogs_vs_clips/evals/cogsguard_evals.py +81 -0
- cogames/cogs_vs_clips/evals/diagnostic_evals.py +49 -444
- cogames/cogs_vs_clips/evals/difficulty_variants.py +13 -326
- cogames/cogs_vs_clips/evals/integrated_evals.py +5 -45
- cogames/cogs_vs_clips/evals/spanning_evals.py +9 -180
- cogames/cogs_vs_clips/mission.py +187 -146
- cogames/cogs_vs_clips/missions.py +46 -137
- cogames/cogs_vs_clips/procedural.py +8 -8
- cogames/cogs_vs_clips/sites.py +107 -3
- cogames/cogs_vs_clips/stations.py +198 -186
- cogames/cogs_vs_clips/tutorial_missions.py +1 -1
- cogames/cogs_vs_clips/variants.py +25 -476
- cogames/device.py +13 -1
- cogames/{policy/scripted_agent/README.md → docs/SCRIPTED_AGENT.md} +82 -58
- cogames/evaluate.py +18 -30
- cogames/main.py +1434 -243
- cogames/maps/canidate1_1000.map +1 -1
- cogames/maps/canidate1_1000_stations.map +2 -2
- cogames/maps/canidate1_500.map +1 -1
- cogames/maps/canidate1_500_stations.map +2 -2
- cogames/maps/canidate2_1000.map +1 -1
- cogames/maps/canidate2_1000_stations.map +2 -2
- cogames/maps/canidate2_500.map +1 -1
- cogames/maps/canidate2_500_stations.map +2 -2
- cogames/maps/canidate3_1000.map +1 -1
- cogames/maps/canidate3_1000_stations.map +2 -2
- cogames/maps/canidate3_500.map +1 -1
- cogames/maps/canidate3_500_stations.map +2 -2
- cogames/maps/canidate4_500.map +1 -1
- cogames/maps/canidate4_500_stations.map +2 -2
- cogames/maps/cave_base_50.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_agile_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_charge_up.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_charge_up_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation1_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation2_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_navigation3_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_near.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_search.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_chest_search_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_extract_lab.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_extract_lab_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_memory.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_memory_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_radial.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_radial_hard.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_resource_lab.map +2 -2
- cogames/maps/diagnostic_evals/diagnostic_unclip.map +2 -2
- cogames/maps/evals/eval_balanced_spread.map +9 -5
- cogames/maps/evals/eval_clip_oxygen.map +9 -5
- cogames/maps/evals/eval_collect_resources.map +9 -5
- cogames/maps/evals/eval_collect_resources_hard.map +9 -5
- cogames/maps/evals/eval_collect_resources_medium.map +9 -5
- cogames/maps/evals/eval_divide_and_conquer.map +9 -5
- cogames/maps/evals/eval_energy_starved.map +9 -5
- cogames/maps/evals/eval_multi_coordinated_collect_hard.map +9 -5
- cogames/maps/evals/eval_oxygen_bottleneck.map +9 -5
- cogames/maps/evals/eval_single_use_world.map +9 -5
- cogames/maps/evals/extractor_hub_100x100.map +9 -5
- cogames/maps/evals/extractor_hub_30x30.map +9 -5
- cogames/maps/evals/extractor_hub_50x50.map +9 -5
- cogames/maps/evals/extractor_hub_70x70.map +9 -5
- cogames/maps/evals/extractor_hub_80x80.map +9 -5
- cogames/maps/machina_100_stations.map +2 -2
- cogames/maps/machina_200_stations.map +2 -2
- cogames/maps/machina_200_stations_small.map +2 -2
- cogames/maps/machina_eval_exp01.map +2 -2
- cogames/maps/machina_eval_template_large.map +2 -2
- cogames/maps/machinatrainer4agents.map +2 -2
- cogames/maps/machinatrainer4agentsbase.map +2 -2
- cogames/maps/machinatrainerbig.map +2 -2
- cogames/maps/machinatrainersmall.map +2 -2
- cogames/maps/planky_evals/aligner_avoid_aoe.map +28 -0
- cogames/maps/planky_evals/aligner_full_cycle.map +28 -0
- cogames/maps/planky_evals/aligner_gear.map +24 -0
- cogames/maps/planky_evals/aligner_hearts.map +24 -0
- cogames/maps/planky_evals/aligner_junction.map +26 -0
- cogames/maps/planky_evals/exploration_distant.map +28 -0
- cogames/maps/planky_evals/maze.map +32 -0
- cogames/maps/planky_evals/miner_best_resource.map +26 -0
- cogames/maps/planky_evals/miner_deposit.map +24 -0
- cogames/maps/planky_evals/miner_extract.map +26 -0
- cogames/maps/planky_evals/miner_full_cycle.map +28 -0
- cogames/maps/planky_evals/miner_gear.map +24 -0
- cogames/maps/planky_evals/multi_role.map +28 -0
- cogames/maps/planky_evals/resource_chain.map +30 -0
- cogames/maps/planky_evals/scout_explore.map +32 -0
- cogames/maps/planky_evals/scout_gear.map +24 -0
- cogames/maps/planky_evals/scrambler_full_cycle.map +28 -0
- cogames/maps/planky_evals/scrambler_gear.map +24 -0
- cogames/maps/planky_evals/scrambler_target.map +26 -0
- cogames/maps/planky_evals/stuck_corridor.map +32 -0
- cogames/maps/planky_evals/survive_retreat.map +26 -0
- cogames/maps/training_facility_clipped.map +2 -2
- cogames/maps/training_facility_open_1.map +2 -2
- cogames/maps/training_facility_open_2.map +2 -2
- cogames/maps/training_facility_open_3.map +2 -2
- cogames/maps/training_facility_tight_4.map +2 -2
- cogames/maps/training_facility_tight_5.map +2 -2
- cogames/maps/vanilla_large.map +2 -2
- cogames/maps/vanilla_small.map +2 -2
- cogames/pickup.py +183 -0
- cogames/play.py +166 -33
- cogames/policy/chaos_monkey.py +54 -0
- cogames/policy/nim_agents/__init__.py +27 -10
- cogames/policy/nim_agents/agents.py +121 -60
- cogames/policy/nim_agents/thinky_eval.py +35 -222
- cogames/policy/pufferlib_policy.py +67 -32
- cogames/policy/starter_agent.py +184 -0
- cogames/policy/trainable_policy_template.py +4 -1
- cogames/train.py +51 -13
- cogames/verbose.py +2 -2
- cogames-0.3.64.dist-info/METADATA +1842 -0
- cogames-0.3.64.dist-info/RECORD +159 -0
- cogames-0.3.64.dist-info/licenses/LICENSE +21 -0
- cogames-0.3.64.dist-info/top_level.txt +2 -0
- metta_alo/__init__.py +0 -0
- metta_alo/job_specs.py +17 -0
- metta_alo/policy.py +16 -0
- metta_alo/pure_single_episode_runner.py +75 -0
- metta_alo/py.typed +0 -0
- metta_alo/rollout.py +322 -0
- metta_alo/scoring.py +168 -0
- cogames/maps/diagnostic_evals/diagnostic_assembler_near.map +0 -49
- cogames/maps/diagnostic_evals/diagnostic_assembler_search.map +0 -49
- cogames/maps/diagnostic_evals/diagnostic_assembler_search_hard.map +0 -89
- cogames/policy/nim_agents/common.nim +0 -887
- cogames/policy/nim_agents/install.sh +0 -1
- cogames/policy/nim_agents/ladybug_agent.nim +0 -984
- cogames/policy/nim_agents/nim_agents.nim +0 -55
- cogames/policy/nim_agents/nim_agents.nims +0 -14
- cogames/policy/nim_agents/nimby.lock +0 -3
- cogames/policy/nim_agents/racecar_agents.nim +0 -884
- cogames/policy/nim_agents/random_agents.nim +0 -68
- cogames/policy/nim_agents/test_agents.py +0 -53
- cogames/policy/nim_agents/thinky_agents.nim +0 -717
- cogames/policy/scripted_agent/baseline_agent.py +0 -1049
- cogames/policy/scripted_agent/demo_policy.py +0 -244
- cogames/policy/scripted_agent/pathfinding.py +0 -126
- cogames/policy/scripted_agent/starter_agent.py +0 -136
- cogames/policy/scripted_agent/types.py +0 -235
- cogames/policy/scripted_agent/unclipping_agent.py +0 -476
- cogames/policy/scripted_agent/utils.py +0 -385
- cogames-0.3.49.dist-info/METADATA +0 -406
- cogames-0.3.49.dist-info/RECORD +0 -136
- cogames-0.3.49.dist-info/top_level.txt +0 -1
- {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/WHEEL +0 -0
- {cogames-0.3.49.dist-info → cogames-0.3.64.dist-info}/entry_points.txt +0 -0
|
@@ -1,884 +0,0 @@
|
|
|
1
|
-
import
|
|
2
|
-
std/[strformat, tables, random, sets, options, json, deques],
|
|
3
|
-
fidget2/measure,
|
|
4
|
-
common
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
MaxEnergy = 100
|
|
8
|
-
MaxResourceInventory = 100
|
|
9
|
-
MaxToolInventory = 100
|
|
10
|
-
MaxStepsDefault = 10000
|
|
11
|
-
|
|
12
|
-
PutCarbonAmount = 10
|
|
13
|
-
PutOxygenAmount = 10
|
|
14
|
-
PutGermaniumAmount = 1
|
|
15
|
-
PutSiliconAmount = 25
|
|
16
|
-
|
|
17
|
-
type
|
|
18
|
-
RaceCarAgent* = ref object
|
|
19
|
-
agentId*: int
|
|
20
|
-
|
|
21
|
-
maxSteps: int
|
|
22
|
-
steps: int
|
|
23
|
-
map: Table[Location, seq[FeatureValue]]
|
|
24
|
-
seen: HashSet[Location]
|
|
25
|
-
unreachable: HashSet[Location]
|
|
26
|
-
depleted: HashSet[Location] # extractors/chargers with remainingUses == 0
|
|
27
|
-
cfg: Config
|
|
28
|
-
random: Rand
|
|
29
|
-
location: Location
|
|
30
|
-
lastActions: seq[int]
|
|
31
|
-
recipes: seq[RecipeInfo]
|
|
32
|
-
|
|
33
|
-
carbonTarget: int
|
|
34
|
-
oxygenTarget: int
|
|
35
|
-
germaniumTarget: int
|
|
36
|
-
siliconTarget: int
|
|
37
|
-
|
|
38
|
-
assignedVibe: Option[int] # desired vibe for vibe-check recipes
|
|
39
|
-
needsPatternReapply: bool # if we changed vibe away from pattern for a side-task
|
|
40
|
-
|
|
41
|
-
bump: bool
|
|
42
|
-
offsets4: seq[Location] # 4 cardinal but random for each agent
|
|
43
|
-
seenAssembler: bool
|
|
44
|
-
seenChest: bool
|
|
45
|
-
assemblerHome: Option[Location]
|
|
46
|
-
chestHome: Option[Location]
|
|
47
|
-
exploreLocations: seq[Location]
|
|
48
|
-
|
|
49
|
-
RaceCarPolicy* = ref object
|
|
50
|
-
agents*: seq[RaceCarAgent]
|
|
51
|
-
|
|
52
|
-
proc log(message: string) =
|
|
53
|
-
when defined(debug):
|
|
54
|
-
echo message
|
|
55
|
-
|
|
56
|
-
const Offsets4 = [
|
|
57
|
-
Location(x: -1, y: +0),
|
|
58
|
-
Location(x: +0, y: +1),
|
|
59
|
-
Location(x: +0, y: -1),
|
|
60
|
-
Location(x: +1, y: +0),
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
const Offsets8 = [
|
|
64
|
-
Location(x: +0, y: +0),
|
|
65
|
-
Location(x: +0, y: +1),
|
|
66
|
-
Location(x: +0, y: -1),
|
|
67
|
-
Location(x: +1, y: +0),
|
|
68
|
-
Location(x: +1, y: +1),
|
|
69
|
-
Location(x: +1, y: -1),
|
|
70
|
-
Location(x: -1, y: +0),
|
|
71
|
-
Location(x: -1, y: +1),
|
|
72
|
-
Location(x: -1, y: -1),
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
proc getActiveRecipe(agent: RaceCarAgent): RecipeInfo {.measure.} =
|
|
76
|
-
## Get the recipes form the assembler protocol inputs.
|
|
77
|
-
let assemblerLocation = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.assembler)
|
|
78
|
-
if assemblerLocation.isSome():
|
|
79
|
-
let location = assemblerLocation.get()
|
|
80
|
-
# Get the vibe key.
|
|
81
|
-
result.pattern = @[]
|
|
82
|
-
for offsets in Offsets8:
|
|
83
|
-
let vibeKey = agent.cfg.getVibe(agent.map, location + offsets)
|
|
84
|
-
if vibeKey != -1:
|
|
85
|
-
result.pattern.add(vibeKey)
|
|
86
|
-
|
|
87
|
-
# Get the required resources.
|
|
88
|
-
let assemblerFeatures = agent.map[location]
|
|
89
|
-
for feature in assemblerFeatures:
|
|
90
|
-
if feature.featureId == agent.cfg.features.protocolInputEnergy:
|
|
91
|
-
result.energyCost = feature.value
|
|
92
|
-
elif feature.featureId == agent.cfg.features.protocolInputCarbon:
|
|
93
|
-
result.carbonCost = feature.value
|
|
94
|
-
elif feature.featureId == agent.cfg.features.protocolInputOxygen:
|
|
95
|
-
result.oxygenCost = feature.value
|
|
96
|
-
elif feature.featureId == agent.cfg.features.protocolInputGermanium:
|
|
97
|
-
result.germaniumCost = feature.value
|
|
98
|
-
elif feature.featureId == agent.cfg.features.protocolInputSilicon:
|
|
99
|
-
result.siliconCost = feature.value
|
|
100
|
-
elif feature.featureId == agent.cfg.features.protocolInputHeart:
|
|
101
|
-
result.heartCost = feature.value
|
|
102
|
-
elif feature.featureId == agent.cfg.features.protocolInputDecoder:
|
|
103
|
-
result.decoderCost = feature.value
|
|
104
|
-
elif feature.featureId == agent.cfg.features.protocolInputModulator:
|
|
105
|
-
result.modulatorCost = feature.value
|
|
106
|
-
elif feature.featureId == agent.cfg.features.protocolInputResonator:
|
|
107
|
-
result.resonatorCost = feature.value
|
|
108
|
-
elif feature.featureId == agent.cfg.features.protocolInputScrambler:
|
|
109
|
-
result.scramblerCost = feature.value
|
|
110
|
-
|
|
111
|
-
elif feature.featureId == agent.cfg.features.protocolOutputEnergy:
|
|
112
|
-
result.energyOutput = feature.value
|
|
113
|
-
elif feature.featureId == agent.cfg.features.protocolOutputCarbon:
|
|
114
|
-
result.carbonOutput = feature.value
|
|
115
|
-
elif feature.featureId == agent.cfg.features.protocolOutputOxygen:
|
|
116
|
-
result.oxygenOutput = feature.value
|
|
117
|
-
elif feature.featureId == agent.cfg.features.protocolOutputGermanium:
|
|
118
|
-
result.germaniumOutput = feature.value
|
|
119
|
-
elif feature.featureId == agent.cfg.features.protocolOutputSilicon:
|
|
120
|
-
result.siliconOutput = feature.value
|
|
121
|
-
elif feature.featureId == agent.cfg.features.protocolOutputHeart:
|
|
122
|
-
result.heartOutput = feature.value
|
|
123
|
-
elif feature.featureId == agent.cfg.features.protocolOutputDecoder:
|
|
124
|
-
result.decoderOutput = feature.value
|
|
125
|
-
elif feature.featureId == agent.cfg.features.protocolOutputModulator:
|
|
126
|
-
result.modulatorOutput = feature.value
|
|
127
|
-
elif feature.featureId == agent.cfg.features.protocolOutputResonator:
|
|
128
|
-
result.resonatorOutput = feature.value
|
|
129
|
-
elif feature.featureId == agent.cfg.features.protocolOutputScrambler:
|
|
130
|
-
result.scramblerOutput = feature.value
|
|
131
|
-
|
|
132
|
-
proc newRaceCarAgent*(agentId: int, environmentConfig: string): RaceCarAgent =
|
|
133
|
-
## Create a new racecar agent, the fastest and the smartest agent.
|
|
134
|
-
|
|
135
|
-
var config = parseConfig(environmentConfig)
|
|
136
|
-
result = RaceCarAgent(agentId: agentId, cfg: config)
|
|
137
|
-
result.maxSteps = MaxStepsDefault
|
|
138
|
-
# Try to read max_steps from the environment config; fall back to default.
|
|
139
|
-
try:
|
|
140
|
-
let env = environmentConfig.parseJson()
|
|
141
|
-
if env.hasKey("game") and env["game"].hasKey("max_steps"):
|
|
142
|
-
result.maxSteps = env["game"]["max_steps"].getInt()
|
|
143
|
-
elif env.hasKey("max_steps"):
|
|
144
|
-
result.maxSteps = env["max_steps"].getInt()
|
|
145
|
-
except CatchableError:
|
|
146
|
-
discard
|
|
147
|
-
result.random = initRand(agentId)
|
|
148
|
-
result.map = initTable[Location, seq[FeatureValue]]()
|
|
149
|
-
result.seen = initHashSet[Location]()
|
|
150
|
-
result.unreachable = initHashSet[Location]()
|
|
151
|
-
result.depleted = initHashSet[Location]()
|
|
152
|
-
result.location = Location(x: 0, y: 0)
|
|
153
|
-
result.assignedVibe = none(int)
|
|
154
|
-
result.needsPatternReapply = false
|
|
155
|
-
result.steps = 0
|
|
156
|
-
result.assemblerHome = none(Location)
|
|
157
|
-
result.chestHome = none(Location)
|
|
158
|
-
result.lastActions = @[]
|
|
159
|
-
# Randomize the offsets4 for each agent, so they take different directions.
|
|
160
|
-
var offsets4 = Offsets4
|
|
161
|
-
result.random.shuffle(offsets4)
|
|
162
|
-
result.offsets4 = @[]
|
|
163
|
-
for o in offsets4:
|
|
164
|
-
result.offsets4.add(o)
|
|
165
|
-
|
|
166
|
-
result.exploreLocations = @[
|
|
167
|
-
Location(x: -7, y: 0),
|
|
168
|
-
Location(x: 0, y: +7),
|
|
169
|
-
Location(x: +7, y: 0),
|
|
170
|
-
Location(x: 0, y: -7),
|
|
171
|
-
]
|
|
172
|
-
result.random.shuffle(result.exploreLocations)
|
|
173
|
-
|
|
174
|
-
proc updateMap(agent: RaceCarAgent, visible: Table[Location, seq[FeatureValue]]) {.measure.} =
|
|
175
|
-
## Update the big map with the small visible map.
|
|
176
|
-
|
|
177
|
-
if agent.map.len == 0:
|
|
178
|
-
# First time we're called, just copy the visible map to the big map.
|
|
179
|
-
agent.map = visible
|
|
180
|
-
agent.location = Location(x: 0, y: 0)
|
|
181
|
-
for x in -5 .. 5:
|
|
182
|
-
for y in -5 .. 5:
|
|
183
|
-
let visibleLocation = Location(x: x, y: y)
|
|
184
|
-
agent.seen.incl(visibleLocation)
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
var newLocation = agent.location
|
|
188
|
-
let lastAction = agent.cfg.getLastAction(visible)
|
|
189
|
-
if lastAction == agent.cfg.actions.moveNorth:
|
|
190
|
-
newLocation.y -= 1
|
|
191
|
-
elif lastAction == agent.cfg.actions.moveSouth:
|
|
192
|
-
newLocation.y += 1
|
|
193
|
-
elif lastAction == agent.cfg.actions.moveWest:
|
|
194
|
-
newLocation.x -= 1
|
|
195
|
-
elif lastAction == agent.cfg.actions.moveEast:
|
|
196
|
-
newLocation.x += 1
|
|
197
|
-
|
|
198
|
-
# Does the new location have force any tags to no be there?
|
|
199
|
-
# If so we did a bump instead of a move.
|
|
200
|
-
block bumpCheck:
|
|
201
|
-
agent.bump = false
|
|
202
|
-
for x in -5 .. 5:
|
|
203
|
-
for y in -5 .. 5:
|
|
204
|
-
let visibleLocation = Location(x: x, y: y)
|
|
205
|
-
let mapLocation = Location(x: x + newLocation.x, y: y + newLocation.y)
|
|
206
|
-
if mapLocation notin agent.seen:
|
|
207
|
-
continue
|
|
208
|
-
var visibleTag = agent.cfg.getTag(visible, visibleLocation)
|
|
209
|
-
if visibleTag == agent.cfg.tags.agent:
|
|
210
|
-
# Ignore agents.
|
|
211
|
-
visibleTag = -1
|
|
212
|
-
var mapTag = agent.cfg.getTag(agent.map, mapLocation)
|
|
213
|
-
if mapTag == agent.cfg.tags.agent:
|
|
214
|
-
# Ignore agents.
|
|
215
|
-
mapTag = -1
|
|
216
|
-
if visibleTag != mapTag:
|
|
217
|
-
newLocation = agent.location
|
|
218
|
-
agent.bump = true
|
|
219
|
-
break bumpCheck
|
|
220
|
-
|
|
221
|
-
# Update the seen set.
|
|
222
|
-
agent.location = newLocation
|
|
223
|
-
for x in -5 .. 5:
|
|
224
|
-
for y in -5 .. 5:
|
|
225
|
-
let visibleLocation = Location(x: x, y: y)
|
|
226
|
-
let mapLocation = Location(x: x + agent.location.x, y: y + agent.location.y)
|
|
227
|
-
if visibleLocation in visible:
|
|
228
|
-
agent.map[mapLocation] = visible[visibleLocation]
|
|
229
|
-
# Mark depleted sites to avoid revisits.
|
|
230
|
-
for f in visible[visibleLocation]:
|
|
231
|
-
if f.featureId == agent.cfg.features.remainingUses and f.value == 0:
|
|
232
|
-
agent.depleted.incl(mapLocation)
|
|
233
|
-
else:
|
|
234
|
-
agent.map[mapLocation] = @[]
|
|
235
|
-
agent.seen.incl(mapLocation)
|
|
236
|
-
|
|
237
|
-
# agent.cfg.drawMap(agent.map, agent.seen)
|
|
238
|
-
|
|
239
|
-
proc getNumAgentsNearby*(
|
|
240
|
-
cfg: Config,
|
|
241
|
-
location: Location,
|
|
242
|
-
map: Table[Location, seq[FeatureValue]]
|
|
243
|
-
): int {.measure.} =
|
|
244
|
-
## Get the number of agents nearby.
|
|
245
|
-
for offset in Offsets8:
|
|
246
|
-
let at = location + offset
|
|
247
|
-
if at in map:
|
|
248
|
-
for featureValue in map[at]:
|
|
249
|
-
if featureValue.featureId == cfg.features.group:
|
|
250
|
-
result += 1
|
|
251
|
-
break
|
|
252
|
-
|
|
253
|
-
proc getNearbyExtractor*(
|
|
254
|
-
cfg: Config,
|
|
255
|
-
currentLocation: Location,
|
|
256
|
-
map: Table[Location, seq[FeatureValue]],
|
|
257
|
-
tagId: int
|
|
258
|
-
): Option[Location] =
|
|
259
|
-
## Get if there is a nearby location with the given tag.
|
|
260
|
-
var
|
|
261
|
-
found = false
|
|
262
|
-
closestLocation = Location(x: 0, y: 0)
|
|
263
|
-
closestDistance = 9999
|
|
264
|
-
for location, featureValues in map:
|
|
265
|
-
for featureValue in featureValues:
|
|
266
|
-
if featureValue.featureId == cfg.features.tag and featureValue.value == tagId:
|
|
267
|
-
let agentsNearby = cfg.getNumAgentsNearby(location, map)
|
|
268
|
-
if agentsNearby > 1:
|
|
269
|
-
continue
|
|
270
|
-
var skip = false
|
|
271
|
-
for f in map[location]:
|
|
272
|
-
if f.featureId == cfg.features.remainingUses and f.value == 0:
|
|
273
|
-
skip = true
|
|
274
|
-
break
|
|
275
|
-
# if f.featureId == cfg.features.cooldownRemaining and f.value > 50:
|
|
276
|
-
# skip = true
|
|
277
|
-
# break
|
|
278
|
-
if skip:
|
|
279
|
-
continue
|
|
280
|
-
let distance = manhattan(location, currentLocation)
|
|
281
|
-
if distance < closestDistance:
|
|
282
|
-
closestDistance = distance
|
|
283
|
-
closestLocation = location
|
|
284
|
-
found = true
|
|
285
|
-
if found:
|
|
286
|
-
return some(closestLocation)
|
|
287
|
-
return none(Location)
|
|
288
|
-
|
|
289
|
-
proc step*(
|
|
290
|
-
agent: RaceCarAgent,
|
|
291
|
-
numAgents: int,
|
|
292
|
-
numTokens: int,
|
|
293
|
-
sizeToken: int,
|
|
294
|
-
rawObservation: pointer,
|
|
295
|
-
numActions: int,
|
|
296
|
-
agentAction: ptr int32
|
|
297
|
-
) {.measure.} =
|
|
298
|
-
try:
|
|
299
|
-
|
|
300
|
-
let observations = cast[ptr UncheckedArray[uint8]](rawObservation)
|
|
301
|
-
|
|
302
|
-
# Parse the tokens into a vision map.
|
|
303
|
-
var visible: Table[Location, seq[FeatureValue]]
|
|
304
|
-
for token in 0 ..< numTokens:
|
|
305
|
-
let locationPacked = observations[token * sizeToken]
|
|
306
|
-
let featureId = observations[token * sizeToken + 1]
|
|
307
|
-
let value = observations[token * sizeToken + 2]
|
|
308
|
-
if locationPacked == 255 and featureId == 255 and value == 255:
|
|
309
|
-
break
|
|
310
|
-
var location: Location
|
|
311
|
-
if locationPacked != 0xFF:
|
|
312
|
-
location.y = (locationPacked shr 4).int - 5
|
|
313
|
-
location.x = (locationPacked and 0x0F).int - 5
|
|
314
|
-
if location notin visible:
|
|
315
|
-
visible[location] = @[]
|
|
316
|
-
visible[location].add(FeatureValue(featureId: featureId.int, value: value.int))
|
|
317
|
-
|
|
318
|
-
proc doAction(action: int) {.measure.} =
|
|
319
|
-
|
|
320
|
-
# Get last action from observations, in case something else moved us.
|
|
321
|
-
agent.lastActions.add(agent.cfg.getLastAction(visible))
|
|
322
|
-
|
|
323
|
-
# Helper to set action without modifying history again.
|
|
324
|
-
proc setAction(actionToSet: int32) =
|
|
325
|
-
agentAction[] = actionToSet
|
|
326
|
-
|
|
327
|
-
# Stuck prevention: if last 2 actions are oscillating, sometimes noop.
|
|
328
|
-
if agent.lastActions.len >= 2:
|
|
329
|
-
if action == agent.cfg.actions.moveWest and
|
|
330
|
-
agent.lastActions[^1] == agent.cfg.actions.moveEast and
|
|
331
|
-
agent.lastActions[^2] == agent.cfg.actions.moveWest:
|
|
332
|
-
if agent.random.rand(1 .. 2) == 1:
|
|
333
|
-
log "Stuck prevention: left, right, left"
|
|
334
|
-
setAction(agent.cfg.actions.noop.int32)
|
|
335
|
-
return
|
|
336
|
-
elif action == agent.cfg.actions.moveEast and
|
|
337
|
-
agent.lastActions[^1] == agent.cfg.actions.moveWest and
|
|
338
|
-
agent.lastActions[^2] == agent.cfg.actions.moveEast:
|
|
339
|
-
if agent.random.rand(1 .. 2) == 1:
|
|
340
|
-
log "Stuck prevention: right, left, right"
|
|
341
|
-
setAction(agent.cfg.actions.noop.int32)
|
|
342
|
-
return
|
|
343
|
-
elif action == agent.cfg.actions.moveNorth and
|
|
344
|
-
agent.lastActions[^1] == agent.cfg.actions.moveSouth and
|
|
345
|
-
agent.lastActions[^2] == agent.cfg.actions.moveNorth:
|
|
346
|
-
if agent.random.rand(1 .. 2) == 1:
|
|
347
|
-
log "Stuck prevention: north, south, north"
|
|
348
|
-
setAction(agent.cfg.actions.noop.int32)
|
|
349
|
-
return
|
|
350
|
-
elif action == agent.cfg.actions.moveSouth and
|
|
351
|
-
agent.lastActions[^1] == agent.cfg.actions.moveNorth and
|
|
352
|
-
agent.lastActions[^2] == agent.cfg.actions.moveSouth:
|
|
353
|
-
if agent.random.rand(1 .. 2) == 1:
|
|
354
|
-
log "Stuck prevention: south, north, south"
|
|
355
|
-
setAction(agent.cfg.actions.noop.int32)
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
setAction(action.int32)
|
|
359
|
-
|
|
360
|
-
updateMap(agent, visible)
|
|
361
|
-
agent.steps += 1
|
|
362
|
-
|
|
363
|
-
# Track base infrastructure as soon as we see it and seed exploration around it
|
|
364
|
-
let assemblerNearbyNow = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.assembler)
|
|
365
|
-
if assemblerNearbyNow.isSome():
|
|
366
|
-
let asmLoc = assemblerNearbyNow.get()
|
|
367
|
-
agent.assemblerHome = some(asmLoc)
|
|
368
|
-
if not agent.seenAssembler:
|
|
369
|
-
agent.seenAssembler = true
|
|
370
|
-
let keyLocations = [
|
|
371
|
-
Location(x: -10, y: -10),
|
|
372
|
-
Location(x: -10, y: +10),
|
|
373
|
-
Location(x: +10, y: -10),
|
|
374
|
-
Location(x: +10, y: +10),
|
|
375
|
-
Location(x: -20, y: 0),
|
|
376
|
-
Location(x: +20, y: 0),
|
|
377
|
-
Location(x: 0, y: -20),
|
|
378
|
-
Location(x: 0, y: +20),
|
|
379
|
-
]
|
|
380
|
-
for keyLocation in keyLocations:
|
|
381
|
-
let location = asmLoc + keyLocation
|
|
382
|
-
if location notin agent.exploreLocations:
|
|
383
|
-
agent.exploreLocations.add(location)
|
|
384
|
-
|
|
385
|
-
let chestNearbyNow = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
386
|
-
if chestNearbyNow.isSome():
|
|
387
|
-
let chestLoc = chestNearbyNow.get()
|
|
388
|
-
agent.chestHome = some(chestLoc)
|
|
389
|
-
if not agent.seenChest:
|
|
390
|
-
agent.seenChest = true
|
|
391
|
-
let keyLocations = [
|
|
392
|
-
Location(x: -3, y: 0),
|
|
393
|
-
Location(x: 0, y: +3),
|
|
394
|
-
Location(x: +3, y: 0),
|
|
395
|
-
Location(x: 0, y: -3),
|
|
396
|
-
Location(x: -6, y: 0),
|
|
397
|
-
Location(x: 0, y: +6),
|
|
398
|
-
Location(x: +6, y: 0),
|
|
399
|
-
Location(x: 0, y: -6),
|
|
400
|
-
]
|
|
401
|
-
for keyLocation in keyLocations:
|
|
402
|
-
let location = chestLoc + keyLocation
|
|
403
|
-
if location notin agent.exploreLocations:
|
|
404
|
-
agent.exploreLocations.add(location)
|
|
405
|
-
|
|
406
|
-
let
|
|
407
|
-
vibe = agent.cfg.getVibe(visible, Location(x: 0, y: 0))
|
|
408
|
-
invEnergy = agent.cfg.getInventory(visible, agent.cfg.features.invEnergy)
|
|
409
|
-
invCarbon = agent.cfg.getInventory(visible, agent.cfg.features.invCarbon)
|
|
410
|
-
invOxygen = agent.cfg.getInventory(visible, agent.cfg.features.invOxygen)
|
|
411
|
-
invGermanium = agent.cfg.getInventory(visible, agent.cfg.features.invGermanium)
|
|
412
|
-
invSilicon = agent.cfg.getInventory(visible, agent.cfg.features.invSilicon)
|
|
413
|
-
invHeart = agent.cfg.getInventory(visible, agent.cfg.features.invHeart)
|
|
414
|
-
invDecoder = agent.cfg.getInventory(visible, agent.cfg.features.invDecoder)
|
|
415
|
-
invModulator = agent.cfg.getInventory(visible, agent.cfg.features.invModulator)
|
|
416
|
-
invResonator = agent.cfg.getInventory(visible, agent.cfg.features.invResonator)
|
|
417
|
-
invScrambler = agent.cfg.getInventory(visible, agent.cfg.features.invScrambler)
|
|
418
|
-
completionPct = agent.cfg.getInventory(visible, agent.cfg.features.episodeCompletionPct)
|
|
419
|
-
|
|
420
|
-
var stepsRemaining = max(0, agent.maxSteps - agent.steps)
|
|
421
|
-
if completionPct > 0 and completionPct < 100:
|
|
422
|
-
# Estimate total steps from observed completion percentage.
|
|
423
|
-
let estTotal = int((agent.steps * 100) div completionPct)
|
|
424
|
-
stepsRemaining = max(0, estTotal - agent.steps)
|
|
425
|
-
|
|
426
|
-
log &"vibe:{vibe} H:{invHeart} E:{invEnergy} C:{invCarbon} O2:{invOxygen} Ge:{invGermanium} Si:{invSilicon} D:{invDecoder} M:{invModulator} R:{invResonator} S:{invScrambler}"
|
|
427
|
-
|
|
428
|
-
let activeRecipe = agent.getActiveRecipe()
|
|
429
|
-
log "active recipe: " & $activeRecipe
|
|
430
|
-
|
|
431
|
-
# If only one resource is needed, make it the sole target to avoid wasted trips.
|
|
432
|
-
var numNeeded = 0
|
|
433
|
-
for cost in [activeRecipe.carbonCost, activeRecipe.oxygenCost, activeRecipe.germaniumCost, activeRecipe.siliconCost]:
|
|
434
|
-
if cost > 0:
|
|
435
|
-
inc numNeeded
|
|
436
|
-
|
|
437
|
-
if activeRecipe.pattern.len > 0:
|
|
438
|
-
# Split the cost evenly across the agents.
|
|
439
|
-
proc divUp(a, b: int): int =
|
|
440
|
-
## Like div, but rounds up instead of down.
|
|
441
|
-
let extra = if a mod b > 0: 1 else: 0
|
|
442
|
-
return a div b + extra
|
|
443
|
-
agent.carbonTarget = max(agent.carbonTarget, activeRecipe.carbonCost.divUp(activeRecipe.pattern.len))
|
|
444
|
-
agent.oxygenTarget = max(agent.oxygenTarget, activeRecipe.oxygenCost.divUp(activeRecipe.pattern.len))
|
|
445
|
-
agent.germaniumTarget = max(agent.germaniumTarget, activeRecipe.germaniumCost.divUp(activeRecipe.pattern.len))
|
|
446
|
-
agent.siliconTarget = max(agent.siliconTarget, activeRecipe.siliconCost.divUp(activeRecipe.pattern.len))
|
|
447
|
-
else:
|
|
448
|
-
agent.carbonTarget = max(agent.carbonTarget, activeRecipe.carbonCost)
|
|
449
|
-
agent.oxygenTarget = max(agent.oxygenTarget, activeRecipe.oxygenCost)
|
|
450
|
-
agent.germaniumTarget = max(agent.germaniumTarget, activeRecipe.germaniumCost)
|
|
451
|
-
agent.siliconTarget = max(agent.siliconTarget, activeRecipe.siliconCost)
|
|
452
|
-
|
|
453
|
-
if numNeeded == 1:
|
|
454
|
-
# Only keep the required resource; zero out others so we don't waste time or dump it.
|
|
455
|
-
if activeRecipe.carbonCost > 0:
|
|
456
|
-
agent.oxygenTarget = 0
|
|
457
|
-
agent.germaniumTarget = 0
|
|
458
|
-
agent.siliconTarget = 0
|
|
459
|
-
elif activeRecipe.oxygenCost > 0:
|
|
460
|
-
agent.carbonTarget = 0
|
|
461
|
-
agent.germaniumTarget = 0
|
|
462
|
-
agent.siliconTarget = 0
|
|
463
|
-
elif activeRecipe.germaniumCost > 0:
|
|
464
|
-
agent.carbonTarget = 0
|
|
465
|
-
agent.oxygenTarget = 0
|
|
466
|
-
agent.siliconTarget = 0
|
|
467
|
-
elif activeRecipe.siliconCost > 0:
|
|
468
|
-
agent.carbonTarget = 0
|
|
469
|
-
agent.oxygenTarget = 0
|
|
470
|
-
agent.germaniumTarget = 0
|
|
471
|
-
|
|
472
|
-
# Vibe-check support: assign and enforce a required vibe from the assembler pattern.
|
|
473
|
-
proc actionForVibe(cfg: Config, v: int): Option[int] =
|
|
474
|
-
if v == cfg.vibes.default: return some(cfg.actions.vibeDefault)
|
|
475
|
-
if v == cfg.vibes.charger: return some(cfg.actions.vibeCharger)
|
|
476
|
-
if v == cfg.vibes.carbonA: return some(cfg.actions.vibeCarbonA)
|
|
477
|
-
if v == cfg.vibes.carbonB: return some(cfg.actions.vibeCarbonB)
|
|
478
|
-
if v == cfg.vibes.oxygenA: return some(cfg.actions.vibeOxygenA)
|
|
479
|
-
if v == cfg.vibes.oxygenB: return some(cfg.actions.vibeOxygenB)
|
|
480
|
-
if v == cfg.vibes.germaniumA: return some(cfg.actions.vibeGermaniumA)
|
|
481
|
-
if v == cfg.vibes.germaniumB: return some(cfg.actions.vibeGermaniumB)
|
|
482
|
-
if v == cfg.vibes.siliconA: return some(cfg.actions.vibeSiliconA)
|
|
483
|
-
if v == cfg.vibes.siliconB: return some(cfg.actions.vibeSiliconB)
|
|
484
|
-
if v == cfg.vibes.heartA: return some(cfg.actions.vibeHeartA)
|
|
485
|
-
if v == cfg.vibes.heartB: return some(cfg.actions.vibeHeartB)
|
|
486
|
-
if v == cfg.vibes.gear: return some(cfg.actions.vibeGear)
|
|
487
|
-
if v == cfg.vibes.assembler: return some(cfg.actions.vibeAssembler)
|
|
488
|
-
if v == cfg.vibes.chest: return some(cfg.actions.vibeChest)
|
|
489
|
-
if v == cfg.vibes.wall: return some(cfg.actions.vibeWall)
|
|
490
|
-
return none(int)
|
|
491
|
-
|
|
492
|
-
template markPatternReapply(v: int) =
|
|
493
|
-
if activeRecipe.pattern.len > 0 and agent.assignedVibe.isSome() and v != agent.assignedVibe.get():
|
|
494
|
-
agent.needsPatternReapply = true
|
|
495
|
-
|
|
496
|
-
if activeRecipe.pattern.len > 0:
|
|
497
|
-
# Assign required vibe: if more agents than vibes, duplicate the first vibe to keep full coverage.
|
|
498
|
-
var haveAssigned = false
|
|
499
|
-
if agent.assignedVibe.isSome():
|
|
500
|
-
for v in activeRecipe.pattern:
|
|
501
|
-
if v == agent.assignedVibe.get():
|
|
502
|
-
haveAssigned = true
|
|
503
|
-
break
|
|
504
|
-
if not haveAssigned:
|
|
505
|
-
let idx = if agent.agentId < activeRecipe.pattern.len: agent.agentId else: 0
|
|
506
|
-
agent.assignedVibe = some(activeRecipe.pattern[idx])
|
|
507
|
-
|
|
508
|
-
proc patternSatisfied(agent: RaceCarAgent): bool =
|
|
509
|
-
# Check if all required vibes are present around the assembler location we know.
|
|
510
|
-
if agent.assemblerHome.isNone():
|
|
511
|
-
return false
|
|
512
|
-
let asmLoc = agent.assemblerHome.get()
|
|
513
|
-
var seenVibes: HashSet[int]
|
|
514
|
-
for offset in Offsets8:
|
|
515
|
-
let loc = asmLoc + offset
|
|
516
|
-
let v = agent.cfg.getVibe(agent.map, loc)
|
|
517
|
-
if v != -1:
|
|
518
|
-
seenVibes.incl(v)
|
|
519
|
-
for v in activeRecipe.pattern:
|
|
520
|
-
if v notin seenVibes:
|
|
521
|
-
return false
|
|
522
|
-
return true
|
|
523
|
-
|
|
524
|
-
let desiredVibe = agent.assignedVibe.get()
|
|
525
|
-
if not patternSatisfied(agent) and (vibe != desiredVibe or agent.needsPatternReapply):
|
|
526
|
-
let vibeAction = actionForVibe(agent.cfg, desiredVibe)
|
|
527
|
-
if vibeAction.isSome():
|
|
528
|
-
doAction(vibeAction.get().int32)
|
|
529
|
-
log "setting vibe to match assembler pattern: " & $desiredVibe
|
|
530
|
-
agent.needsPatternReapply = false
|
|
531
|
-
return
|
|
532
|
-
|
|
533
|
-
# Are we running low on energy?
|
|
534
|
-
if invEnergy < MaxEnergy div 4:
|
|
535
|
-
let chargerNearby = agent.cfg.getNearbyExtractor(agent.location, agent.map, agent.cfg.tags.charger)
|
|
536
|
-
if chargerNearby.isSome():
|
|
537
|
-
measurePush("charger nearby")
|
|
538
|
-
let action = agent.cfg.aStar(agent.location, chargerNearby.get(), agent.map)
|
|
539
|
-
measurePop()
|
|
540
|
-
if action.isSome():
|
|
541
|
-
doAction(action.get().int32)
|
|
542
|
-
log "going to charger"
|
|
543
|
-
return
|
|
544
|
-
|
|
545
|
-
# Charge opportunistically, with a slightly higher margin for hard energy maps.
|
|
546
|
-
let opportunisticMargin = if stepsRemaining < 200: MaxEnergy - 30 else: MaxEnergy - 20
|
|
547
|
-
if invEnergy < opportunisticMargin:
|
|
548
|
-
let chargerNearby = agent.cfg.getNearbyExtractor(agent.location, agent.map, agent.cfg.tags.charger)
|
|
549
|
-
if chargerNearby.isSome():
|
|
550
|
-
if manhattan(agent.location, chargerNearby.get()) < 2:
|
|
551
|
-
measurePush("charge nearby")
|
|
552
|
-
let action = agent.cfg.aStar(agent.location, chargerNearby.get(), agent.map)
|
|
553
|
-
measurePop()
|
|
554
|
-
if action.isSome():
|
|
555
|
-
doAction(action.get().int32)
|
|
556
|
-
log "charge nearby might as well charge"
|
|
557
|
-
return
|
|
558
|
-
|
|
559
|
-
# Deposit heart into the chest.
|
|
560
|
-
if invHeart > 0:
|
|
561
|
-
|
|
562
|
-
# Reset the targets when we deposit hearts.
|
|
563
|
-
log "depositing hearts"
|
|
564
|
-
agent.carbonTarget = PutCarbonAmount
|
|
565
|
-
agent.oxygenTarget = PutOxygenAmount
|
|
566
|
-
agent.germaniumTarget = PutGermaniumAmount
|
|
567
|
-
agent.siliconTarget = PutSiliconAmount
|
|
568
|
-
|
|
569
|
-
let depositAction = agent.cfg.actions.vibeHeartB
|
|
570
|
-
let depositVibe = agent.cfg.vibes.heartB
|
|
571
|
-
if depositAction != 0 and vibe != depositVibe:
|
|
572
|
-
doAction(depositAction.int32)
|
|
573
|
-
markPatternReapply(depositVibe)
|
|
574
|
-
return
|
|
575
|
-
let chestNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
576
|
-
if chestNearby.isSome():
|
|
577
|
-
measurePush("chest nearby")
|
|
578
|
-
let action = agent.cfg.aStar(agent.location, chestNearby.get(), agent.map)
|
|
579
|
-
measurePop()
|
|
580
|
-
if action.isSome():
|
|
581
|
-
doAction(action.get().int32)
|
|
582
|
-
log "going to chest"
|
|
583
|
-
return
|
|
584
|
-
|
|
585
|
-
# Build a heart when we have the full recipe.
|
|
586
|
-
if invCarbon >= agent.carbonTarget and invOxygen >= agent.oxygenTarget and invGermanium >= agent.germaniumTarget and invSilicon >= agent.siliconTarget:
|
|
587
|
-
log "trying to build a heart"
|
|
588
|
-
|
|
589
|
-
if vibe != agent.cfg.vibes.heartA:
|
|
590
|
-
doAction(agent.cfg.actions.vibeHeartA.int32)
|
|
591
|
-
markPatternReapply(agent.cfg.vibes.heartA)
|
|
592
|
-
log "vibing heart for assembler"
|
|
593
|
-
return
|
|
594
|
-
|
|
595
|
-
let assemblerNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.assembler)
|
|
596
|
-
if assemblerNearby.isSome():
|
|
597
|
-
measurePush("assembler nearby")
|
|
598
|
-
let action = agent.cfg.aStar(agent.location, assemblerNearby.get(), agent.map)
|
|
599
|
-
measurePop()
|
|
600
|
-
if action.isSome():
|
|
601
|
-
doAction(action.get().int32)
|
|
602
|
-
log "going to assembler to build heart"
|
|
603
|
-
return
|
|
604
|
-
|
|
605
|
-
# Dump excess resources.
|
|
606
|
-
let atMaxInventory = invCarbon + invOxygen + invGermanium + invSilicon >= MaxResourceInventory
|
|
607
|
-
let avgResource = (invCarbon + invOxygen + invGermanium + invSilicon) div 4
|
|
608
|
-
if atMaxInventory:
|
|
609
|
-
log "at max inventory"
|
|
610
|
-
|
|
611
|
-
if atMaxInventory and invCarbon > avgResource and invCarbon > agent.carbonTarget + PutCarbonAmount and agent.carbonTarget == 0:
|
|
612
|
-
let chestNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
613
|
-
if chestNearby.isSome():
|
|
614
|
-
if vibe != agent.cfg.vibes.carbonB:
|
|
615
|
-
doAction(agent.cfg.actions.vibeCarbonB.int32)
|
|
616
|
-
markPatternReapply(agent.cfg.vibes.carbonB)
|
|
617
|
-
log "vibing carbon B to dump excess carbon"
|
|
618
|
-
return
|
|
619
|
-
measurePush("chest nearby excess carbon")
|
|
620
|
-
let action = agent.cfg.aStar(agent.location, chestNearby.get(), agent.map)
|
|
621
|
-
measurePop()
|
|
622
|
-
if action.isSome():
|
|
623
|
-
doAction(action.get().int32)
|
|
624
|
-
log "going to chest to dump excess carbon"
|
|
625
|
-
return
|
|
626
|
-
|
|
627
|
-
if atMaxInventory and invSilicon > avgResource and invSilicon > agent.siliconTarget + PutSiliconAmount and agent.siliconTarget == 0:
|
|
628
|
-
let chestNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
629
|
-
if chestNearby.isSome():
|
|
630
|
-
if vibe != agent.cfg.vibes.siliconB:
|
|
631
|
-
doAction(agent.cfg.actions.vibeSiliconB.int32)
|
|
632
|
-
markPatternReapply(agent.cfg.vibes.siliconB)
|
|
633
|
-
log "vibing silicon B to dump excess silicon"
|
|
634
|
-
return
|
|
635
|
-
let action = agent.cfg.aStar(agent.location, chestNearby.get(), agent.map)
|
|
636
|
-
if action.isSome():
|
|
637
|
-
doAction(action.get().int32)
|
|
638
|
-
log "going to chest to dump excess silicon"
|
|
639
|
-
return
|
|
640
|
-
|
|
641
|
-
if atMaxInventory and invOxygen > avgResource and invOxygen > agent.oxygenTarget + PutOxygenAmount and agent.oxygenTarget == 0:
|
|
642
|
-
let chestNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
643
|
-
if chestNearby.isSome():
|
|
644
|
-
if vibe != agent.cfg.vibes.oxygenB:
|
|
645
|
-
doAction(agent.cfg.actions.vibeOxygenB.int32)
|
|
646
|
-
markPatternReapply(agent.cfg.vibes.oxygenB)
|
|
647
|
-
log "vibing oxygen B to dump excess oxygen"
|
|
648
|
-
return
|
|
649
|
-
measurePush("chest nearby excess oxygen")
|
|
650
|
-
let action = agent.cfg.aStar(agent.location, chestNearby.get(), agent.map)
|
|
651
|
-
measurePop()
|
|
652
|
-
if action.isSome():
|
|
653
|
-
doAction(action.get().int32)
|
|
654
|
-
log "going to chest to dump excess oxygen"
|
|
655
|
-
return
|
|
656
|
-
|
|
657
|
-
if atMaxInventory and invGermanium > avgResource and invGermanium > agent.germaniumTarget + PutGermaniumAmount and agent.germaniumTarget == 0:
|
|
658
|
-
let chestNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
659
|
-
if chestNearby.isSome():
|
|
660
|
-
if vibe != agent.cfg.vibes.germaniumB:
|
|
661
|
-
doAction(agent.cfg.actions.vibeGermaniumB.int32)
|
|
662
|
-
markPatternReapply(agent.cfg.vibes.germaniumB)
|
|
663
|
-
log "vibing germanium B to dump excess germanium"
|
|
664
|
-
return
|
|
665
|
-
measurePush("chest nearby excess germanium")
|
|
666
|
-
let action = agent.cfg.aStar(agent.location, chestNearby.get(), agent.map)
|
|
667
|
-
measurePop()
|
|
668
|
-
if action.isSome():
|
|
669
|
-
doAction(action.get().int32)
|
|
670
|
-
log "going to chest to dump excess germanium"
|
|
671
|
-
return
|
|
672
|
-
|
|
673
|
-
# Distance-aware late return: aim to arrive before the episode ends.
|
|
674
|
-
if agent.assemblerHome.isSome():
|
|
675
|
-
let distAsm = manhattan(agent.location, agent.assemblerHome.get())
|
|
676
|
-
let buffer = 30
|
|
677
|
-
if stepsRemaining <= distAsm + buffer:
|
|
678
|
-
if invHeart > 0:
|
|
679
|
-
let target = if agent.chestHome.isSome(): agent.chestHome.get() else: agent.assemblerHome.get()
|
|
680
|
-
let action = agent.cfg.aStar(agent.location, target, agent.map)
|
|
681
|
-
if action.isSome():
|
|
682
|
-
doAction(action.get().int32)
|
|
683
|
-
log "late return: delivering hearts"
|
|
684
|
-
return
|
|
685
|
-
elif invCarbon + invOxygen + invGermanium + invSilicon > 0:
|
|
686
|
-
let action = agent.cfg.aStar(agent.location, agent.assemblerHome.get(), agent.map)
|
|
687
|
-
if action.isSome():
|
|
688
|
-
doAction(action.get().int32)
|
|
689
|
-
log "late return: heading to assembler with resources"
|
|
690
|
-
return
|
|
691
|
-
|
|
692
|
-
proc findAndTakeResource(
|
|
693
|
-
agent: RaceCarAgent,
|
|
694
|
-
vibe: int,
|
|
695
|
-
resource: int,
|
|
696
|
-
target: int,
|
|
697
|
-
inventory: int,
|
|
698
|
-
vibeGetResource: int,
|
|
699
|
-
vibeAction: int,
|
|
700
|
-
extractorTag: int,
|
|
701
|
-
name: string
|
|
702
|
-
): bool {.measure.} =
|
|
703
|
-
# Check the chest.
|
|
704
|
-
var closeChest = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.chest)
|
|
705
|
-
if closeChest.isSome():
|
|
706
|
-
# Does it have the resources we need?
|
|
707
|
-
let chestInventory = agent.cfg.getInventory(agent.map, resource, closeChest.get())
|
|
708
|
-
if chestInventory > 0:
|
|
709
|
-
# Vibe the right resource to take from the chest.
|
|
710
|
-
if vibe != vibeGetResource:
|
|
711
|
-
doAction(vibeAction.int32)
|
|
712
|
-
log "vibing " & name & " to take from chest"
|
|
713
|
-
return true
|
|
714
|
-
measurePush("chest nearby to take " & name)
|
|
715
|
-
let action = agent.cfg.aStar(agent.location, closeChest.get(), agent.map)
|
|
716
|
-
measurePop()
|
|
717
|
-
if action.isSome():
|
|
718
|
-
doAction(action.get().int32)
|
|
719
|
-
log "going to chest to take " & name & " from chest"
|
|
720
|
-
return true
|
|
721
|
-
|
|
722
|
-
# Check the carbon extractor.
|
|
723
|
-
let extractorNearby = agent.cfg.getNearbyExtractor(agent.location, agent.map, extractorTag)
|
|
724
|
-
if extractorNearby.isSome() and extractorNearby.get() notin agent.unreachable and extractorNearby.get() notin agent.depleted:
|
|
725
|
-
measurePush("extractor nearby to take " & name)
|
|
726
|
-
let action = agent.cfg.aStar(agent.location, extractorNearby.get(), agent.map)
|
|
727
|
-
measurePop()
|
|
728
|
-
if action.isSome():
|
|
729
|
-
doAction(action.get().int32)
|
|
730
|
-
log "going to " & name & ", need: " & $target & " have: " & $inventory
|
|
731
|
-
markPatternReapply(vibe)
|
|
732
|
-
# If we arrive and see it depleted, mark it.
|
|
733
|
-
if extractorNearby.get() in agent.depleted:
|
|
734
|
-
agent.unreachable.incl(extractorNearby.get())
|
|
735
|
-
return true
|
|
736
|
-
else:
|
|
737
|
-
agent.unreachable.incl(extractorNearby.get())
|
|
738
|
-
|
|
739
|
-
# Is there carbon nearby?
|
|
740
|
-
if agent.carbonTarget > 0 and invCarbon < agent.carbonTarget:
|
|
741
|
-
if agent.findAndTakeResource(
|
|
742
|
-
vibe,
|
|
743
|
-
agent.cfg.features.invCarbon,
|
|
744
|
-
agent.carbonTarget,
|
|
745
|
-
invCarbon,
|
|
746
|
-
agent.cfg.vibes.carbonA,
|
|
747
|
-
agent.cfg.actions.vibeCarbonA,
|
|
748
|
-
agent.cfg.tags.carbonExtractor,
|
|
749
|
-
"carbon"
|
|
750
|
-
):
|
|
751
|
-
return
|
|
752
|
-
|
|
753
|
-
# Is there silicon nearby?
|
|
754
|
-
if agent.siliconTarget > 0 and invSilicon < agent.siliconTarget:
|
|
755
|
-
if agent.findAndTakeResource(
|
|
756
|
-
vibe,
|
|
757
|
-
agent.cfg.features.invSilicon,
|
|
758
|
-
agent.siliconTarget,
|
|
759
|
-
invSilicon,
|
|
760
|
-
agent.cfg.vibes.siliconA,
|
|
761
|
-
agent.cfg.actions.vibeSiliconA,
|
|
762
|
-
agent.cfg.tags.siliconExtractor,
|
|
763
|
-
"silicon"
|
|
764
|
-
):
|
|
765
|
-
return
|
|
766
|
-
|
|
767
|
-
# Is there oxygen nearby?
|
|
768
|
-
if agent.oxygenTarget > 0 and invOxygen < agent.oxygenTarget:
|
|
769
|
-
if agent.findAndTakeResource(
|
|
770
|
-
vibe,
|
|
771
|
-
agent.cfg.features.invOxygen,
|
|
772
|
-
agent.oxygenTarget,
|
|
773
|
-
invOxygen,
|
|
774
|
-
agent.cfg.vibes.oxygenA,
|
|
775
|
-
agent.cfg.actions.vibeOxygenA,
|
|
776
|
-
agent.cfg.tags.oxygenExtractor,
|
|
777
|
-
"oxygen"
|
|
778
|
-
):
|
|
779
|
-
return
|
|
780
|
-
|
|
781
|
-
# Is there germanium nearby?
|
|
782
|
-
if agent.germaniumTarget > 0 and invGermanium < agent.germaniumTarget:
|
|
783
|
-
if agent.findAndTakeResource(
|
|
784
|
-
vibe,
|
|
785
|
-
agent.cfg.features.invGermanium,
|
|
786
|
-
agent.germaniumTarget,
|
|
787
|
-
invGermanium,
|
|
788
|
-
agent.cfg.vibes.germaniumA,
|
|
789
|
-
agent.cfg.actions.vibeGermaniumA,
|
|
790
|
-
agent.cfg.tags.germaniumExtractor,
|
|
791
|
-
"germanium"
|
|
792
|
-
):
|
|
793
|
-
return
|
|
794
|
-
|
|
795
|
-
# Do Exploration.
|
|
796
|
-
if agent.exploreLocations.len == 0:
|
|
797
|
-
measurePush("exploration")
|
|
798
|
-
var locationFound = false
|
|
799
|
-
var unexploredLocation: Location
|
|
800
|
-
var visited: HashSet[Location]
|
|
801
|
-
block exploration:
|
|
802
|
-
var seedLocation = agent.location
|
|
803
|
-
let assemblerNearby = agent.cfg.getNearby(agent.location, agent.map, agent.cfg.tags.assembler)
|
|
804
|
-
if assemblerNearby.isSome():
|
|
805
|
-
seedLocation = assemblerNearby.get()
|
|
806
|
-
var queue: Deque[Location]
|
|
807
|
-
queue.addLast(seedLocation)
|
|
808
|
-
visited.incl(seedLocation)
|
|
809
|
-
while queue.len > 0:
|
|
810
|
-
let location = queue.popLast()
|
|
811
|
-
if location notin agent.seen:
|
|
812
|
-
locationFound = true
|
|
813
|
-
unexploredLocation = location
|
|
814
|
-
break exploration
|
|
815
|
-
for i, offset in Offsets4:
|
|
816
|
-
let neighbor = location + offset
|
|
817
|
-
# passable check
|
|
818
|
-
if agent.cfg.isWalkable(agent.map, neighbor):
|
|
819
|
-
if neighbor notin visited:
|
|
820
|
-
visited.incl(neighbor)
|
|
821
|
-
queue.addLast(neighbor)
|
|
822
|
-
if locationFound:
|
|
823
|
-
agent.exploreLocations.add(unexploredLocation)
|
|
824
|
-
else:
|
|
825
|
-
log "no unseen location found"
|
|
826
|
-
# agent.cfg.drawMap(agent.map, visited)
|
|
827
|
-
measurePop()
|
|
828
|
-
|
|
829
|
-
measurePush("explore locations")
|
|
830
|
-
log "explore locations: " & $agent.exploreLocations
|
|
831
|
-
if agent.exploreLocations.len > 0:
|
|
832
|
-
for location in agent.exploreLocations:
|
|
833
|
-
if location notin agent.seen:
|
|
834
|
-
let action = agent.cfg.aStar(agent.location, location, agent.map)
|
|
835
|
-
if action.isSome():
|
|
836
|
-
doAction(action.get().int32)
|
|
837
|
-
log "going to explore location: " & $location
|
|
838
|
-
return
|
|
839
|
-
else:
|
|
840
|
-
agent.exploreLocations.remove(location)
|
|
841
|
-
break
|
|
842
|
-
else:
|
|
843
|
-
agent.exploreLocations.remove(location)
|
|
844
|
-
break
|
|
845
|
-
measurePop()
|
|
846
|
-
|
|
847
|
-
# If all else fails, take a random move to explore the map or get unstuck.
|
|
848
|
-
let action = agent.random.rand(1 .. 4).int32
|
|
849
|
-
log "taking random action " & $action
|
|
850
|
-
doAction(action.int32)
|
|
851
|
-
|
|
852
|
-
except:
|
|
853
|
-
echo getCurrentException().getStackTrace()
|
|
854
|
-
echo getCurrentExceptionMsg()
|
|
855
|
-
quit()
|
|
856
|
-
|
|
857
|
-
proc newRaceCarPolicy*(environmentConfig: string): RaceCarPolicy =
|
|
858
|
-
let cfg = parseConfig(environmentConfig)
|
|
859
|
-
var agents: seq[RaceCarAgent] = @[]
|
|
860
|
-
for id in 0 ..< cfg.config.numAgents:
|
|
861
|
-
agents.add(newRaceCarAgent(id, environmentConfig))
|
|
862
|
-
return RaceCarPolicy(agents: agents)
|
|
863
|
-
|
|
864
|
-
proc stepBatch*(
|
|
865
|
-
policy: RaceCarPolicy,
|
|
866
|
-
agentIds: pointer,
|
|
867
|
-
numAgentIds: int,
|
|
868
|
-
numAgents: int,
|
|
869
|
-
numTokens: int,
|
|
870
|
-
sizeToken: int,
|
|
871
|
-
rawObservations: pointer,
|
|
872
|
-
numActions: int,
|
|
873
|
-
rawActions: pointer
|
|
874
|
-
) {.measure.} =
|
|
875
|
-
let ids = cast[ptr UncheckedArray[int32]](agentIds)
|
|
876
|
-
let obsArray = cast[ptr UncheckedArray[uint8]](rawObservations)
|
|
877
|
-
let actionArray = cast[ptr UncheckedArray[int32]](rawActions)
|
|
878
|
-
let obsStride = numTokens * sizeToken
|
|
879
|
-
|
|
880
|
-
for i in 0 ..< numAgentIds:
|
|
881
|
-
let idx = int(ids[i])
|
|
882
|
-
let obsPtr = cast[pointer](obsArray[idx * obsStride].addr)
|
|
883
|
-
let actPtr = cast[ptr int32](actionArray[idx].addr)
|
|
884
|
-
step(policy.agents[idx], numAgents, numTokens, sizeToken, obsPtr, numActions, actPtr)
|