goapauto 0.1.0__tar.gz

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.
@@ -0,0 +1,291 @@
1
+ Metadata-Version: 2.4
2
+ Name: goapauto
3
+ Version: 0.1.0
4
+ Summary: A flexible Goal-Oriented Action Planning (GOAP) system for game AI and planning problems, featuring A* search, efficient state management, and modular design.
5
+ Requires-Python: >=3.13
6
+ Description-Content-Type: text/markdown
7
+
8
+ # GOAP Planner
9
+
10
+ A flexible Goal-Oriented Action Planning (GOAP) system designed for game AI, but applicable to any planning problem. This implementation provides a clean, modular architecture for defining actions, goals, and world states to create intelligent AI behaviors.
11
+
12
+ ## Features
13
+
14
+ - 🎯 Goal-oriented planning with customizable actions and preconditions
15
+ - 🧠 A* search algorithm for optimal plan generation
16
+ - âš¡ Efficient state management and caching
17
+ - 📊 Built-in planning statistics and debugging
18
+ - 🧩 Modular design for easy extension
19
+ - 🎮 Example implementations included
20
+
21
+ ## Installation
22
+
23
+ ### From PyPI
24
+ ```bash
25
+ uv add goapauto
26
+ ```
27
+
28
+ ### From Source
29
+ 1. Clone the repository:
30
+ ```bash
31
+ git clone https://github.com/IAmNo1Special/goapauto.git
32
+ cd goapauto
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ from models.goap_planner import Planner, PlanResult
39
+ from models.goal import Goal
40
+ from models.actions import Action, Actions
41
+ from models.worldstate import WorldState
42
+
43
+ # Define your initial state using WorldState for better type safety and validation
44
+ initial_state = WorldState({
45
+ 'is_open': False,
46
+ 'is_focused': False,
47
+ 'has_key': True,
48
+ 'energy': 100
49
+ })
50
+
51
+ # Create actions collection
52
+ actions = Actions()
53
+
54
+ # Add actions with proper typing and validation
55
+ try:
56
+ actions.add_action(
57
+ name="open_door",
58
+ preconditions={'is_open': False, 'has_key': True},
59
+ effects={'is_open': True},
60
+ cost=1.0
61
+ )
62
+
63
+ actions.add_action(
64
+ name="consume_energy",
65
+ preconditions={'energy': (lambda x: x > 0)},
66
+ effects={'energy': (lambda x: x - 10)},
67
+ cost=1.0
68
+ )
69
+ except (ValueError, TypeError) as e:
70
+ print(f"Error creating actions: {e}")
71
+ raise
72
+
73
+ # Create a goal with validation
74
+ try:
75
+ goal = Goal(
76
+ name="Open Door",
77
+ priority=1,
78
+ target_state={'is_open': True}
79
+ )
80
+ except ValueError as e:
81
+ print(f"Invalid goal: {e}")
82
+ raise
83
+
84
+ # Create and run the planner
85
+ planner = Planner(actions)
86
+ plan, message = planner.generate_plan(initial_state, goal)
87
+
88
+ # The planner will automatically display the plan and statistics
89
+ # You can access the plan and execute it if needed
90
+ if plan is not None:
91
+ current_state = initial_state.copy()
92
+ for i, action_name in enumerate(plan, 1):
93
+ action = actions.get_action(action_name)
94
+ print(f"\nStep {i}: {action_name}")
95
+ current_state = action.apply(current_state)
96
+ print(f"New state: {current_state}")
97
+ ```
98
+
99
+ ## Project Structure
100
+
101
+ - `/models` - Core GOAP implementation
102
+ - `goap_planner.py` - Main planner logic
103
+ - `goal.py` - Goal definition and management
104
+ - `actions.py` - Action definitions
105
+ - `worldstate.py` - World state management
106
+ - `node.py` - Search node implementation
107
+
108
+ - `/examples` - Example implementations
109
+ - `example1.py` - Basic usage example
110
+ - `example2.py` - Advanced scenario
111
+
112
+ ## Advanced Usage
113
+
114
+ ### Working with WorldState
115
+
116
+ ```python
117
+ from models.worldstate import WorldState
118
+
119
+ # Create a state with validation
120
+ state = WorldState({
121
+ 'health': 100,
122
+ 'has_weapon': True,
123
+ 'enemy_visible': False
124
+ })
125
+
126
+ # Safe state updates
127
+ state = state.merge({'health': 80}) # Returns new state
128
+ state = state.copy() # Create a deep copy
129
+
130
+ # Check conditions
131
+ if state.matches({'health': (lambda x: x > 50)}):
132
+ print("Health is above 50%")
133
+ ```
134
+
135
+ ### Creating Custom Actions
136
+
137
+ Define actions using the `Action` class for better type safety and validation:
138
+
139
+ ```python
140
+ from models.actions import Action, Actions
141
+
142
+ # Create a single action
143
+ open_door = Action(
144
+ name="open_door",
145
+ preconditions={'door_locked': False},
146
+ effects={'door_open': True},
147
+ cost=1.0
148
+ )
149
+
150
+ # Or use the Actions collection to manage multiple actions
151
+ actions = Actions()
152
+ actions.add_action(
153
+ name="unlock_door",
154
+ preconditions={'has_key': True},
155
+ effects={'door_locked': False},
156
+ cost=1.5
157
+ )
158
+
159
+ # Add multiple actions at once
160
+ actions.add_actions([
161
+ ("pick_up_item", {"near_item": True}, {"has_item": True}, 1.0),
162
+ ("use_item", {"has_item": True}, {"effect_applied": True}, 1.0)
163
+ ])
164
+
165
+ # Check if an action is applicable in a given state
166
+ if open_door.is_applicable(current_state):
167
+ new_state = open_door.apply(current_state)
168
+ ```
169
+
170
+ ### Defininig Goals with target states and priorities
171
+
172
+ ```python
173
+ from models.goal import Goal
174
+
175
+ goal = Goal(
176
+ name="Achieve Objective",
177
+ priority=1,
178
+ target_state={
179
+ 'objective_complete': True
180
+ }
181
+ )
182
+ ```
183
+
184
+ ### Defining Goals with Conditions
185
+
186
+ ```python
187
+ from models.goal import Goal
188
+
189
+ # Simple goal
190
+ goal = Goal(
191
+ name="Defeat Enemy",
192
+ priority=1,
193
+ target_state={
194
+ 'enemy_defeated': True,
195
+ 'health': (lambda x: x > 0) # Must have health remaining
196
+ }
197
+ )
198
+
199
+ # Goal with custom validation
200
+ try:
201
+ goal.validate()
202
+ except ValueError as e:
203
+ print(f"Invalid goal: {e}")
204
+ ```
205
+
206
+ ### Working with Plan Results
207
+
208
+ ```python
209
+ # After generating a plan
210
+ if plan is not None:
211
+ print(f"Plan found with {len(plan)} actions")
212
+ print(f"Total cost: {planner.stats.total_cost}")
213
+ print(f"Nodes expanded: {planner.stats.nodes_expanded}")
214
+ print(f"Planning time: {planner.stats.execution_time:.4f}s")
215
+
216
+ # Access individual plan steps
217
+ for i, action_name in enumerate(plan, 1):
218
+ action = actions.get_action(action_name)
219
+ print(f"{i}. {action_name} (cost: {action.cost})")
220
+
221
+ # Execute the plan and track state changes
222
+ current_state = initial_state.copy()
223
+ for i, action_name in enumerate(plan, 1):
224
+ action = actions.get_action(action_name)
225
+ print(f"\nStep {i}: {action_name}")
226
+ current_state = action.apply(current_state)
227
+ print(f"State after action: {current_state}")
228
+ ```
229
+
230
+ ### Custom Heuristics
231
+
232
+ ```python
233
+ from models.goap_planner import Planner
234
+
235
+ def custom_heuristic(state, goal_state):
236
+ """Custom heuristic function for A* search."""
237
+ # Implement your heuristic logic here
238
+ # Lower values mean closer to goal
239
+ return 0 # Default to Dijkstra's algorithm
240
+
241
+ planner = Planner(actions, heuristic=custom_heuristic)
242
+ ```
243
+
244
+ ## Performance Tips
245
+
246
+ 1. **State Design**:
247
+ - Keep state keys simple and consistent
248
+ - Use immutable state objects for better caching
249
+
250
+ 2. **Action Design**:
251
+ - Make preconditions as specific as possible
252
+ - Use lambda functions for dynamic conditions
253
+ - Keep effects minimal and focused
254
+
255
+ 3. **Debugging**:
256
+ - Enable debug logging for detailed planning info
257
+ - Check PlanResult.stats for performance metrics
258
+ - Use state validation to catch issues early
259
+
260
+ ## Troubleshooting
261
+
262
+ ### Common Issues
263
+
264
+ 1. **No Plan Found**
265
+ - Check if actions' preconditions are met
266
+ - Verify the goal is achievable
267
+ - Increase max_iterations if needed
268
+
269
+ 2. **Performance Problems**
270
+ - Check for infinite state spaces
271
+ - Add more specific preconditions
272
+ - Consider using a custom heuristic
273
+
274
+
275
+ ## Running Examples
276
+
277
+ ```bash
278
+ # Run basic example
279
+ python examples/example1.py
280
+
281
+ # Run advanced example
282
+ python examples/example2.py
283
+ ```
284
+
285
+ ## Contributing
286
+
287
+ Contributions are welcome! Please feel free to submit a Pull Request.
288
+
289
+ ## License
290
+
291
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,284 @@
1
+ # GOAP Planner
2
+
3
+ A flexible Goal-Oriented Action Planning (GOAP) system designed for game AI, but applicable to any planning problem. This implementation provides a clean, modular architecture for defining actions, goals, and world states to create intelligent AI behaviors.
4
+
5
+ ## Features
6
+
7
+ - 🎯 Goal-oriented planning with customizable actions and preconditions
8
+ - 🧠 A* search algorithm for optimal plan generation
9
+ - âš¡ Efficient state management and caching
10
+ - 📊 Built-in planning statistics and debugging
11
+ - 🧩 Modular design for easy extension
12
+ - 🎮 Example implementations included
13
+
14
+ ## Installation
15
+
16
+ ### From PyPI
17
+ ```bash
18
+ uv add goapauto
19
+ ```
20
+
21
+ ### From Source
22
+ 1. Clone the repository:
23
+ ```bash
24
+ git clone https://github.com/IAmNo1Special/goapauto.git
25
+ cd goapauto
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```python
31
+ from models.goap_planner import Planner, PlanResult
32
+ from models.goal import Goal
33
+ from models.actions import Action, Actions
34
+ from models.worldstate import WorldState
35
+
36
+ # Define your initial state using WorldState for better type safety and validation
37
+ initial_state = WorldState({
38
+ 'is_open': False,
39
+ 'is_focused': False,
40
+ 'has_key': True,
41
+ 'energy': 100
42
+ })
43
+
44
+ # Create actions collection
45
+ actions = Actions()
46
+
47
+ # Add actions with proper typing and validation
48
+ try:
49
+ actions.add_action(
50
+ name="open_door",
51
+ preconditions={'is_open': False, 'has_key': True},
52
+ effects={'is_open': True},
53
+ cost=1.0
54
+ )
55
+
56
+ actions.add_action(
57
+ name="consume_energy",
58
+ preconditions={'energy': (lambda x: x > 0)},
59
+ effects={'energy': (lambda x: x - 10)},
60
+ cost=1.0
61
+ )
62
+ except (ValueError, TypeError) as e:
63
+ print(f"Error creating actions: {e}")
64
+ raise
65
+
66
+ # Create a goal with validation
67
+ try:
68
+ goal = Goal(
69
+ name="Open Door",
70
+ priority=1,
71
+ target_state={'is_open': True}
72
+ )
73
+ except ValueError as e:
74
+ print(f"Invalid goal: {e}")
75
+ raise
76
+
77
+ # Create and run the planner
78
+ planner = Planner(actions)
79
+ plan, message = planner.generate_plan(initial_state, goal)
80
+
81
+ # The planner will automatically display the plan and statistics
82
+ # You can access the plan and execute it if needed
83
+ if plan is not None:
84
+ current_state = initial_state.copy()
85
+ for i, action_name in enumerate(plan, 1):
86
+ action = actions.get_action(action_name)
87
+ print(f"\nStep {i}: {action_name}")
88
+ current_state = action.apply(current_state)
89
+ print(f"New state: {current_state}")
90
+ ```
91
+
92
+ ## Project Structure
93
+
94
+ - `/models` - Core GOAP implementation
95
+ - `goap_planner.py` - Main planner logic
96
+ - `goal.py` - Goal definition and management
97
+ - `actions.py` - Action definitions
98
+ - `worldstate.py` - World state management
99
+ - `node.py` - Search node implementation
100
+
101
+ - `/examples` - Example implementations
102
+ - `example1.py` - Basic usage example
103
+ - `example2.py` - Advanced scenario
104
+
105
+ ## Advanced Usage
106
+
107
+ ### Working with WorldState
108
+
109
+ ```python
110
+ from models.worldstate import WorldState
111
+
112
+ # Create a state with validation
113
+ state = WorldState({
114
+ 'health': 100,
115
+ 'has_weapon': True,
116
+ 'enemy_visible': False
117
+ })
118
+
119
+ # Safe state updates
120
+ state = state.merge({'health': 80}) # Returns new state
121
+ state = state.copy() # Create a deep copy
122
+
123
+ # Check conditions
124
+ if state.matches({'health': (lambda x: x > 50)}):
125
+ print("Health is above 50%")
126
+ ```
127
+
128
+ ### Creating Custom Actions
129
+
130
+ Define actions using the `Action` class for better type safety and validation:
131
+
132
+ ```python
133
+ from models.actions import Action, Actions
134
+
135
+ # Create a single action
136
+ open_door = Action(
137
+ name="open_door",
138
+ preconditions={'door_locked': False},
139
+ effects={'door_open': True},
140
+ cost=1.0
141
+ )
142
+
143
+ # Or use the Actions collection to manage multiple actions
144
+ actions = Actions()
145
+ actions.add_action(
146
+ name="unlock_door",
147
+ preconditions={'has_key': True},
148
+ effects={'door_locked': False},
149
+ cost=1.5
150
+ )
151
+
152
+ # Add multiple actions at once
153
+ actions.add_actions([
154
+ ("pick_up_item", {"near_item": True}, {"has_item": True}, 1.0),
155
+ ("use_item", {"has_item": True}, {"effect_applied": True}, 1.0)
156
+ ])
157
+
158
+ # Check if an action is applicable in a given state
159
+ if open_door.is_applicable(current_state):
160
+ new_state = open_door.apply(current_state)
161
+ ```
162
+
163
+ ### Defininig Goals with target states and priorities
164
+
165
+ ```python
166
+ from models.goal import Goal
167
+
168
+ goal = Goal(
169
+ name="Achieve Objective",
170
+ priority=1,
171
+ target_state={
172
+ 'objective_complete': True
173
+ }
174
+ )
175
+ ```
176
+
177
+ ### Defining Goals with Conditions
178
+
179
+ ```python
180
+ from models.goal import Goal
181
+
182
+ # Simple goal
183
+ goal = Goal(
184
+ name="Defeat Enemy",
185
+ priority=1,
186
+ target_state={
187
+ 'enemy_defeated': True,
188
+ 'health': (lambda x: x > 0) # Must have health remaining
189
+ }
190
+ )
191
+
192
+ # Goal with custom validation
193
+ try:
194
+ goal.validate()
195
+ except ValueError as e:
196
+ print(f"Invalid goal: {e}")
197
+ ```
198
+
199
+ ### Working with Plan Results
200
+
201
+ ```python
202
+ # After generating a plan
203
+ if plan is not None:
204
+ print(f"Plan found with {len(plan)} actions")
205
+ print(f"Total cost: {planner.stats.total_cost}")
206
+ print(f"Nodes expanded: {planner.stats.nodes_expanded}")
207
+ print(f"Planning time: {planner.stats.execution_time:.4f}s")
208
+
209
+ # Access individual plan steps
210
+ for i, action_name in enumerate(plan, 1):
211
+ action = actions.get_action(action_name)
212
+ print(f"{i}. {action_name} (cost: {action.cost})")
213
+
214
+ # Execute the plan and track state changes
215
+ current_state = initial_state.copy()
216
+ for i, action_name in enumerate(plan, 1):
217
+ action = actions.get_action(action_name)
218
+ print(f"\nStep {i}: {action_name}")
219
+ current_state = action.apply(current_state)
220
+ print(f"State after action: {current_state}")
221
+ ```
222
+
223
+ ### Custom Heuristics
224
+
225
+ ```python
226
+ from models.goap_planner import Planner
227
+
228
+ def custom_heuristic(state, goal_state):
229
+ """Custom heuristic function for A* search."""
230
+ # Implement your heuristic logic here
231
+ # Lower values mean closer to goal
232
+ return 0 # Default to Dijkstra's algorithm
233
+
234
+ planner = Planner(actions, heuristic=custom_heuristic)
235
+ ```
236
+
237
+ ## Performance Tips
238
+
239
+ 1. **State Design**:
240
+ - Keep state keys simple and consistent
241
+ - Use immutable state objects for better caching
242
+
243
+ 2. **Action Design**:
244
+ - Make preconditions as specific as possible
245
+ - Use lambda functions for dynamic conditions
246
+ - Keep effects minimal and focused
247
+
248
+ 3. **Debugging**:
249
+ - Enable debug logging for detailed planning info
250
+ - Check PlanResult.stats for performance metrics
251
+ - Use state validation to catch issues early
252
+
253
+ ## Troubleshooting
254
+
255
+ ### Common Issues
256
+
257
+ 1. **No Plan Found**
258
+ - Check if actions' preconditions are met
259
+ - Verify the goal is achievable
260
+ - Increase max_iterations if needed
261
+
262
+ 2. **Performance Problems**
263
+ - Check for infinite state spaces
264
+ - Add more specific preconditions
265
+ - Consider using a custom heuristic
266
+
267
+
268
+ ## Running Examples
269
+
270
+ ```bash
271
+ # Run basic example
272
+ python examples/example1.py
273
+
274
+ # Run advanced example
275
+ python examples/example2.py
276
+ ```
277
+
278
+ ## Contributing
279
+
280
+ Contributions are welcome! Please feel free to submit a Pull Request.
281
+
282
+ ## License
283
+
284
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.