-
Notifications
You must be signed in to change notification settings - Fork 1
/
goap_scratch.txt
381 lines (169 loc) · 12.5 KB
/
goap_scratch.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
https://chat.openai.com/chat/e4bb4965-c043-4788-bd71-0abc19fa240e
IDEA GARTH VADER:
fallback to generic selector if more specific bound selector doesn't work
Adding a fallback mechanism to use a generic selector when a more specific bound selector doesn't return any valid entity is a good approach. This allows the system to be more adaptable when the optimal choice isn't available, and ensures the planner can still generate a valid plan. This can be particularly useful in situations where the environment or the state of the entities is dynamic and may change during runtime.
IDEA GODZILLA:
histeresis for bind-selecting nodes that failed to interact and broke the plan (we will
try another comparable genericselector node that passes the generic filter)
Introducing hysteresis for bind-selecting nodes based on previous failures during the execution of a plan can make the system more resilient and adaptive. By avoiding nodes that have caused a plan to fail, the planner can learn from its mistakes and try alternative nodes that may be more suitable for the current situation. This approach is especially useful when dealing with dynamic environments where conditions may change, and the same action might have different outcomes depending on the state of the world and the entities involved.
the hysteresis is valuable especially because say some seemingly optimal ox, in order to get it to the field, requires going near bandits. the plan would break due to fight-flight utility supercession during the action "leadOxTOField", which has the bound "ox" as its node. then we would have hysteresis, so we would go get another less optimal ox that may not involve going near the bandits, and we can bring it to the field and farm.
one thing thats a bit of a wrinkle is, you dont necessarily know when to cooldown. maybe the plan broke and you fight/flighted, but then the bandits got disposed of. the old ox is still valid in that case... hmmm
That's a valid concern. In dynamic environments, the circumstances can change rapidly, making it challenging to determine the appropriate cooldown time for a previously failed option. One possible solution to this problem is to use a more adaptive cooldown mechanism that depends on the agent's perception of the environment.
[x] IDEA GREMLIN:
TODO: add rules, valid ranges for IntMap values, so in Set() we can validate these
values being set in a STATE intmap, ultimately so that State can enforce some operations it's impervious to, more often than any other use case, eg:
eggsample being, an ox that can't be yoked = 1, can only be yoked = 0.
and in fact we need to adapt to this in planning. if our bound entity is for some
reason unyokable, it should bubble an err? i guess we would define rules as
NumericInterval's, and when trying to Set the state in the generated effset func,
if we cannot set that value, then the modal eff set will just silently fail to set
the value and then the modal check func will see 0 when the action shuodl've set 1.
modal failure.
summary of the below, feedback by chatGPT:
IDEA GAMMA: Introducing a gather action that symbolically represents gathering of materials is an interesting approach. It can simplify the initial planning process and make it more efficient. However, it may introduce complexities when implementing the actual gathering logic as a prelude to the subsequent actions like building or crafting.
IDEA GEMATRIA: Considering only the actions whose nodes resolve could help improve the efficiency of the GOAP solver by eliminating irrelevant or invalid actions from the search space. This should help in reducing the overall computation time.
IDEA GEM3000: Introducing a dot notation for binding modal values from the blackboard can make it easier to access and manipulate entity-specific data. This notation can enable more complex interactions and queries about entities in the environment, like checking inventory or aggro status.
IDEA GAMMA PRIME: This idea presents a more detailed approach for generating GOAP plans, considering various scenarios and alternative ways to achieve the goals (like crafting, trading, or withdrawal). It demonstrates how a more sophisticated planning system can handle different situations and contingencies.
[ ] IDEA GAMMA: gather is a single action; anything that needs materials can put gather to get symbolically, materials. this way, gather itself
is offlaoded as a separate GOAP.
this is so that a plan that goes far back enough into gathering for crafting/building is quick to terminate as a solution in the initial solver without having to do all the tree walking etc... and then the success
of that plan can be made (should be made) dependent on the success of planning the gathering as a prelude (it will be the first action of such chains, like, [gather, buildHouse] or [gather, craftBow])
and then the gather will look at what materials are needed in bb and plan out something like,
let's say the crafting and building mechanic is a bit magical,
to lay the materials by the fire and go do the build wherever it is, or craft right at the fire, if that's the case.
[x] IDEA GEMATRIA
only consider actions whose nodes resolve aka would succeed in binding.
[x] IDEA GEM3000
implemented the below but instead of bb used STATE intmap
oh, we didn't do inventoryHas(archetype) or .inventoryHasTag(tagstr) or .aggro()
bind the modal val node from bb if we specify the varName with a dot, like field.tilled, it'll automatically go into modalEntity["field"].GetIntMap(STATE).m["tilled"]
this opens up a whole bunch of nice notations, like if we wanted to maybe ask a villager for an item they're carrying, like villager.inventoryHas(bow) would resolve the inventory check for the modal entity villager and the archetype name "bow", or villager.inventoryHasTag(weapon), or animal.aggro, which would check the STATE map for its enemies and return 1 if we are in it
[ ] IDEA GAMMA PRIME (this is the next gen of GOAP testing functions:)
uh oh the below gets hairy, way easier to do this for the individual
in
the utility / some consideration / decorator, there is a write to blackboard that one bow is wanted to be added
to the village stores.
(in the generic case, addedToVillageStore($item, $village), but let's use bow)
so
the corresponding goal is addedToVillageStore(bow, village)
main planning goal: addedToVillageStore(bow, village)
// the legal action of possession of the product: village.appropProduct($item)
addedToVillageStore(bow, village) is satisfied by village.appropProduct(bow)
village.appropProduct(bow) has pre produced(bow)
// the productive act craft($item)
produced(bow) is satisfied by craft(bow)
craft(bow) has pre ingredients(bow)
// the gathering labour of the raw materials, gather($item)
ingredients(bow) is satisfied by gather(bow)
gather(bow) has nil pre
thus:
[gather(bow), craft(bow), village.appropProduct(bow)] is a solution
OR (a trader has it!)
addedToVillageStore(bow, village) is satisfied by village.tradeGet(bow)
village.tradeGet(bow) has nil pre
(if no trader nearby, the modal entity bind for the trader will fail, if the trader exists, this pathway becomes valid)
thus:
[village.trade(bow)]
if something we want to do, like hunt, has pre: has(bow), what do we do?
planning goal (pre of hunt): has(bow)
if has(bow) modally is 0, we don't have it. it wants val 1, the ws will have val 0.
so,
has(bow) is satisfied by village.withdraw(bow) // there are other ways to get a bow
village.withdraw(bow) has pre village.has(bow)
so, in the case that village.has(bow) is 1, village.withdraw()'s pre is satisfied,
and the has(bow) goal is satisfied by the action village.withdraw(bow),
thus
[village.withdraw(bow), hunt]
which is just a parametrised goto+get
(which decays to almost a no-op when the bow is
in the entitiy's inventory, it's just the withdraw() ticketpunch
happens for this entity using this tool in the bb)
but if village.has(bow) is modally 0, the pre is not satisfied,
and this means there is not a single bow.
so
what makes village.has(bow) = 1?
village.has(bow) is satisfied by village.appropProduct(bow)
... pre satisfied by craft(bow)
... pre satisfied by gather(bow)
thus:
[gather(bow), craft(bow), village.appropProduct(bow), village.withdraw(bow)]
NOTE the whole time the entity would have the bow in their inventory, just
we were trying to satisfy
the gather action in the [gather(bow), craft(bow)] case would expand to a GOAP like
[getBowstring, getStick, layRecipe(bow)]
or
[getStick, getBowstring, layRecipe(bow)]
where layRecipe(bow) is an action answering "canCraft(bow)" as the goal
or the gather action in [gather, buildHouse]
[getStone(3), chopTree(3), chopLog(3), layLog(3)]
or
[chopTree(3), chopLog(3), carryWoodToFire]
where buildHouse is itself probably a sequence of animations gated by whehter you have the resources (btree)
what if we formed the intention of wanting to play chess?
we'd push the chess into the pqueue for village production?
we'd produce it then and there ourself if we cant withdraw, like the bow example?
i think to keep track of the fact it might take a long time, this should be
a kind of intention that gets stored on blackboard, that we return to depending
on leisure hours available to devote to it - or maybe if there's enough roles assigned to others that morning, our work curves are zeroed and we have all day leisure to craft the board
[x] IDEA ZETA: don't put any gotos in the plan. just actions. and whenever you perform an action, you're at the node that uses it. so dynamically during runtime, you auto-goto the node of the next part of the action.
similarly, with each action being identified with a spaital node, we can do - during post-processing of possible logical-symbol-and-modal-valid paths, a distance calculation and sort by that
IDEA A: when found a solution, wiggle through all permunations of the unordered goals in the tree (yes this will use regionoffsets and some trickery), and run them modally, comparing for least distance and possibly other criteria (energy cost? money cost?)
SKETCH A:
0 1 2 3 4 5 6
[ [0] [0] [-1 0] [0] [0] [0] [0] ]
[ A B C Y X Cb * ]
[ [q] [r] [s t] [m] [w] [v] [u] ]
where C->u, Cb->u
A->s
B->t Y,X->v
which unordered goals have more than 1 children?
[u].nChildren == 2 (C,Cb)
[v].nChildren == 2 (Y,X)
so our wiggle points are [u] and [v]
*
/ \
C Cb
|\ |\
A B Y X
wiggle u
[A B C] [Y X Cb]
[Y X Cb] [A B C]
for each, wiggle v
[A B C] [X Y Cb]
[X Y Cb] [A B C]
the question becomes, can our heuristic help us avoid the need to check all these permutations?
in theory since we try to satisfy each goal with each action on insert, the alternative orderings of C Cb vs Cb C will arise at the same time. the one that has a shorter distance will get picked up for iteration earlier.
so say we iterate the Cb C wiggle branch since it's better. and we prepend something.
now depending on what we added, the worse wiggle may iterate before this path with the prepend. but at any rate, once we prepend something to this worse wiggle, now we're going to pick up the good wiggle first since it's likely ahead.
IDEA B: "deterministic" mode where unordered temporal ([0]) insertion will not be hashtable random according to which one came up during the search but instead will be sorted alpha
SKETCH B:
0 1 2 3
[ [0] [0] [-1 0] [0] ]
[ A B C * ]
[ [q] [r] [s t] [u] ]
insert Ca for [u] ? unordered... should be after C
ix = i = 3
minix = i - remainings[i].nChildren = 3 - 1
maxix = i
insertionix is: $(binary search [minix,maxix] the insertion point according to string ordering)
here will be 3
0 1 2 3 4 5 6
[ [0] [0] [-1 0] [0] [0] [0] [0] ]
[ A B C Y X Cb * ]
[ [q] [r] [s t] [m] [w] [v] [u] ]
where C->u, Cb->u
A->s
B->t Y,X->v
so [u].nChildren == 2 (C,Cb)
insert Ca for [u]?
our possible insertion ixs are 0, 2, 6
so we don't binary search indexes in the raw array, but we binary search the *children of [u]*,
and then simply lookup*** the ix of where we land (actions store their ixs i think)
IDEA C: heuristic change
sumOfCosts(path) + nUnfulfilled(path.remainings)
has the defect that they are on different (ultimately un)normalized ranges
so what if we multiply them?
sumOfCosts(path) * nUnfulfilled(path.remainings)
that way:
- when we have same costs but less unfulfilled, go for that one
- when we have same unfulfilled but less cost, go for that one