@@ -15,15 +15,30 @@ const (
1515 DIVIDE
1616)
1717
18+ // Action represents a single action that an agent can perform to modify the world state.
19+ //
20+ // An action has preconditions (conditions) that must be met before it can be executed,
21+ // and postconditions (effects) that describe how it modifies the world state.
22+ // Actions have a cost that is used by the A* algorithm to find the optimal plan.
1823type Action struct {
1924 name string
2025 cost float32
2126 repeatable bool
2227 conditions Conditions
2328 effects Effects
2429}
30+
31+ // Actions is a collection of Action pointers.
2532type Actions []* Action
2633
34+ // AddAction creates a new Action and appends it to the Actions collection.
35+ //
36+ // Parameters:
37+ // - name: unique identifier for the action
38+ // - cost: numeric cost used by pathfinding (lower costs are preferred)
39+ // - repeatable: if false, the action can only be used once per plan
40+ // - conditions: preconditions that must be satisfied before the action can be executed
41+ // - effects: postconditions that describe how the action modifies the world state
2742func (actions * Actions ) AddAction (name string , cost float32 , repeatable bool , conditions Conditions , effects Effects ) {
2843 action := Action {
2944 name : name ,
@@ -36,36 +51,50 @@ func (actions *Actions) AddAction(name string, cost float32, repeatable bool, co
3651 * actions = append (* actions , & action )
3752}
3853
54+ // GetName returns the action's name identifier.
3955func (action * Action ) GetName () string {
4056 return action .name
4157}
4258
59+ // GetEffects returns the action's effects (postconditions).
4360func (action * Action ) GetEffects () Effects {
4461 return action .effects
4562}
4663
64+ // EffectInterface defines the interface that all effect types must implement.
65+ // Effects describe how an action modifies the world state.
4766type EffectInterface interface {
48- check (states states ) bool
49- apply (data statesData ) error
67+ GetKey () StateKey
68+ check (w world ) bool
69+ apply (w * world ) error
5070}
5171
72+ // Effect represents a numeric state modification for types constrained by Numeric.
73+ //
74+ // It supports arithmetic operators (SET, ADD, SUBTRACT, MULTIPLY, DIVIDE) to modify
75+ // numeric state values. The effect is applied when an action is executed during planning.
5276type Effect [T Numeric ] struct {
53- Key StateKey
54- Operator arithmetic
55- Value T
77+ Key StateKey // State key to modify
78+ Operator arithmetic // Arithmetic operation to perform
79+ Value T // Value to use in the operation
80+ }
81+
82+ // GetKey returns the state key that this effect modifies.
83+ func (effect Effect [T ]) GetKey () StateKey {
84+ return effect .Key
5685}
5786
58- func (effect Effect [T ]) check (states states ) bool {
59- // Other operators than '=' mean the effect will have an impact of the states
87+ func (effect Effect [T ]) check (w world ) bool {
88+ // Other operators than '=' mean the effect will have an impact of the world
6089 if effect .Operator != SET {
6190 return false
6291 }
6392
64- k := states . data .GetIndex (effect .Key )
93+ k := w . states .GetIndex (effect .Key )
6594 if k < 0 {
6695 return false
6796 }
68- s := states . data [k ]
97+ s := w . states [k ]
6998
7099 if _ , ok := s .(State [T ]); ! ok {
71100 return false
@@ -74,23 +103,23 @@ func (effect Effect[T]) check(states states) bool {
74103 return s .(State [T ]).Value == effect .Value
75104}
76105
77- func (effect Effect [T ]) apply (data statesData ) error {
78- k := data .GetIndex (effect .Key )
106+ func (effect Effect [T ]) apply (w * world ) error {
107+ k := w . states .GetIndex (effect .Key )
79108 if k < 0 {
80109 if slices .Contains ([]arithmetic {SET , ADD }, effect .Operator ) {
81- data = append (data , State [T ]{Value : effect .Value })
110+ w . states = append (w . states , State [T ]{Key : effect . Key , Value : effect .Value })
82111 return nil
83112 } else if slices .Contains ([]arithmetic {SUBSTRACT }, effect .Operator ) {
84- data = append (data , State [T ]{Value : - effect .Value })
113+ w . states = append (w . states , State [T ]{Key : effect . Key , Value : - effect .Value })
85114 return nil
86115 }
87- return fmt .Errorf ("data does not exist" )
116+ return fmt .Errorf ("w does not exist" )
88117 }
89- if _ , ok := data [k ].(State [T ]); ! ok {
118+ if _ , ok := w . states [k ].(State [T ]); ! ok {
90119 return fmt .Errorf ("type does not match" )
91120 }
92121
93- state := data [k ].(State [T ])
122+ state := w . states [k ].(State [T ])
94123 switch effect .Operator {
95124 case SET :
96125 state .Value = effect .Value
@@ -104,129 +133,151 @@ func (effect Effect[T]) apply(data statesData) error {
104133 state .Value /= effect .Value
105134 }
106135
107- data [ k ] = state
136+ state . Store ( w )
108137
109138 return nil
110139}
111140
141+ // EffectBool represents a boolean state modification.
142+ //
143+ // Only the SET operator is allowed for boolean effects. Attempting to use other
144+ // operators (ADD, SUBTRACT, etc.) will result in an error when the effect is applied.
112145type EffectBool struct {
113- Key StateKey
114- Value bool
115- Operator arithmetic
146+ Key StateKey // State key to modify
147+ Value bool // Boolean value to set
148+ Operator arithmetic // Must be SET
116149}
117150
118- func (effectBool EffectBool ) check (states states ) bool {
151+ // GetKey returns the state key that this effect modifies.
152+ func (effectBool EffectBool ) GetKey () StateKey {
153+ return effectBool .Key
154+ }
155+
156+ func (effectBool EffectBool ) check (w world ) bool {
119157 // Other operators than '=' is not allowed
120158 if effectBool .Operator != SET {
121159 return false
122160 }
123161
124- k := states . data .GetIndex (effectBool .Key )
162+ k := w . states .GetIndex (effectBool .Key )
125163 if k < 0 {
126164 return false
127165 }
128- if _ , ok := states . data [k ].(State [bool ]); ! ok {
166+ if _ , ok := w . states [k ].(State [bool ]); ! ok {
129167 return false
130168 }
131169
132- s := states . data [k ].(State [bool ])
170+ s := w . states [k ].(State [bool ])
133171
134172 return s .Value == effectBool .Value
135173}
136174
137- func (effectBool EffectBool ) apply (data statesData ) error {
175+ func (effectBool EffectBool ) apply (w * world ) error {
138176 if effectBool .Operator != SET {
139177 return fmt .Errorf ("operation %v not allowed on bool type" , effectBool .Operator )
140178 }
141179
142- k := data .GetIndex (effectBool .Key )
180+ k := w . states .GetIndex (effectBool .Key )
143181 if k < 0 {
144- data = append (data , State [bool ]{Value : effectBool .Value })
182+ w . states = append (w . states , State [bool ]{Key : effectBool . Key , Value : effectBool .Value })
145183 return nil
146184 }
147- if _ , ok := data [k ].(State [bool ]); ! ok {
185+ if _ , ok := w . states [k ].(State [bool ]); ! ok {
148186 return fmt .Errorf ("type does not match" )
149187 }
150188
151- state := data [k ].(State [bool ])
189+ state := w . states [k ].(State [bool ])
152190 state .Value = effectBool .Value
153- data [k ] = state
191+
192+ state .Store (w )
154193
155194 return nil
156195}
157196
197+ // EffectString represents a string state modification.
198+ //
199+ // Supports SET (replace string) and ADD (concatenate) operators. Other operators
200+ // (SUBTRACT, MULTIPLY, DIVIDE) are not allowed and will result in an error.
158201type EffectString struct {
159- Key StateKey
160- Value string
161- Operator arithmetic
202+ Key StateKey // State key to modify
203+ Value string // String value to use
204+ Operator arithmetic // Allowed: SET, ADD
162205}
163206
164- func (effectString EffectString ) check (states states ) bool {
165- k := states .data .GetIndex (effectString .Key )
207+ // GetKey returns the state key that this effect modifies.
208+ func (effectString EffectString ) GetKey () StateKey {
209+ return effectString .Key
210+ }
211+
212+ func (effectString EffectString ) check (w world ) bool {
213+ k := w .states .GetIndex (effectString .Key )
166214 if k < 0 {
167215 return false
168216 }
169- if _ , ok := states . data [k ].(State [string ]); ! ok {
217+ if _ , ok := w . states [k ].(State [string ]); ! ok {
170218 return false
171219 }
172220
173- s := states . data [k ].(State [string ])
221+ s := w . states [k ].(State [string ])
174222
175223 return s .Value == effectString .Value
176224}
177225
178- func (effectString EffectString ) apply (data statesData ) error {
226+ func (effectString EffectString ) apply (w * world ) error {
179227 if ! slices .Contains ([]arithmetic {SET , ADD }, effectString .Operator ) {
180228 return fmt .Errorf ("arithmetic operation %v not allowed on string type" , effectString .Operator )
181229 }
182230
183- k := data .GetIndex (effectString .Key )
231+ k := w . states .GetIndex (effectString .Key )
184232 if k < 0 {
185- data = append (data , State [string ]{Value : effectString .Value })
233+ w . states = append (w . states , State [string ]{Key : effectString . Key , Value : effectString .Value })
186234 return nil
187235 }
188- if _ , ok := data [k ].(State [string ]); ! ok {
236+ if _ , ok := w . states [k ].(State [string ]); ! ok {
189237 return fmt .Errorf ("type does not match" )
190238 }
191239
192- state := data [k ].(State [string ])
240+ state := w . states [k ].(State [string ])
193241 switch effectString .Operator {
194242 case SET :
195243 state .Value = effectString .Value
196244 case ADD :
197245 state .Value = fmt .Sprint (state .Value , effectString .Value )
198246 }
199- data [k ] = state
247+
248+ state .Store (w )
200249
201250 return nil
202251}
203252
253+ // EffectFn is a function type for custom procedural effects that directly modify the agent.
254+ // This allows for effects that cannot be expressed through simple state modifications.
204255type EffectFn func (agent * Agent )
205256
257+ // Effects is a collection of EffectInterface implementations that describe how
258+ // an action modifies the world state.
206259type Effects []EffectInterface
207260
208- // If all the effects already exist in states ,
261+ // If all the effects already exist in world ,
209262// it is probably not a good path
210- func (effects Effects ) satisfyStates (states states ) bool {
263+ func (effects Effects ) satisfyStates (w world ) bool {
211264 for _ , effect := range effects {
212- if ! effect .check (states ) {
265+ if ! effect .check (w ) {
213266 return false
214267 }
215268 }
216269
217270 return true
218271}
219272
220- func (effects Effects ) apply (states states ) (statesData , error ) {
221- data := slices .Clone (states .data )
222-
273+ func (effects Effects ) apply (w * world ) error {
223274 for _ , effect := range effects {
224- err := effect .apply (data )
275+ err := effect .apply (w )
225276
226277 if err != nil {
227- return nil , err
278+ return err
228279 }
229280 }
230281
231- return data , nil
282+ return nil
232283}
0 commit comments