pyGameAIFoundation is a python package that provides classes for implementing AI in games
Project description
pyGameAIFoundation
Source code: GitHub
pyGameAIFoundation is a python package that provides classes for implementing decision making AI in games. It includes classes for goal-oriented behavior, action execution, and blackboard architecture. A develper can use these foundation classes to implement game goals and actions specific to their game, and to utilize those objects to create goal-based behavior in a game.
Credit where credit is due
- The package generally implements pseudo code from the book "Artificial Intelligence for Games", Second Edtion, by Ian Millington and John Funge, Chapter 5, 2009.
Gob class
The Gob, which is an implementation of Goal-Oriented Behavior. Specifically, it implements the Simple Selection mechanisim for choosing a game action from a set of goals and actions. It implements pseudo code from Section 5.7.2 of "Artificial Intelligence for Games".
GameGoal class
GameGoal is an abstract base class. Concrete implementations of this class represent goals that can be achieved in a game. It implements pseudo code from Section 5.7.2-3 of "Artificial Intelligence for Games".
A concrete implementation must implement the method getInsistence(), which is called to get the
insistence (urgency or importance) value of the goal. The higher the insistence value, the more urgent or important the goal is.
ActionManager class
The ActionManager class manages the scheduling and execution of actions in a game. It implements pseudo code from Section 5.11.3 of "Artificial Intelligence for Games".
GameAction class
GameAction is an abstract base class, GameAction. Concrete implementations of this class represent actions that can be performed in a game. It generally implements pseudo code from Section 5.11.4 of "Artificial Intelligence for Games", The possibility of actions being able to read and write data to a blackboard is additionally included, following the blackboard architecture pattern described in Section 5.9 of the same book.
Concrete implementation child classes of GameAction must:
- Implement the method
execute(), which is called to enact the specific behavior of the action. - Override the method
isComplete(), which is called to determine if the action is completed.
Concrete implementation child classes of GameAction also:
- May override the method
canInterrupt(), which is called to determine if this action can interrupt other actions, e.g., in the active collection of an ActionManager object. - May override the method
canDoBoth(...), which is called to determine of this action can be executed at the same time as another action, e.g., in the active collection of an ActionManager object. - Should override the method
getGoalChange(...), which is called to determine how this action affects the insistence of a specific goal, e.g., in the goal collection maintained by a Gob object. The method should return a negative integer, indicating a reduction in the insistence of the goal when the action is executed.
GameActionCombination class (child of GameAction)
The GameActonCombination class is a child of GameAction, and it represents a combination of game actions that can be performed together (in parallel, at least in the sense of game logic).
GameActionSequence class (child of GameAction)
The GameActionSequence class is a child of GameAction, and it represents a sequence of game actions that must be performed in order in the sense of game logic.
Usage
# Local imports
from pyGameAIFoundation.gob import Gob
from pyGameAIFoundation.game_goal import GameGoal, GoalInsistence
from pyGameAIFoundation.action_manager import ActionManager
from pyGameAIFoundation.game_action import GameAction, GameActionCombination, GameActionSequence
# Create a couple of concrete GameGoal subclasses with different insistence values.
class GoalOne(GameGoal):
def getInsistence(self):
"""
Return the insistence value of the goal.
:return: The insistence value of the goal, int
"""
return GoalInsistence.LOW
class GoalTwo(GameGoal):
def getInsistence(self):
"""
Return the insistence value of the goal.
:return: The insistence value of the goal, int
"""
return GoalInsistence.MEDIUM
# Create a pair of GameAction subclasses with different implementations of getGoalChange(...)
class ActionOne(GameAction):
def __init__(self, expiry_time=0, priority=0, read_blackboard=None, write_blackboard=None):
"""
:parameter expiry_time: The time in an arbitrary count-up from zero until the action expires, as int
:parameter priority: The priority of the action. Higher numbers indicate higher priority. As int
:parameter read_blackboard: A function to read from the blackboard, as callable
Signature: read_blackboard(key: str) -> any
:parameter write_blackboard: A function to write to the blackboard, as callable
Signature: write_blackboard(key: str, value: any) -> None
"""
super().__init__(expiry_time, priority, read_blackboard, write_blackboard)
self._canInterrupt = False
self._canDoBoth = False
self._completed=False
def canInterrupt(self):
"""
Return whether this action can interrupt any other action.
:return: True if the action can interrupt any other action, False otherwise, as boolean.
"""
return self._canInterrupt
def canDoBoth(self, other_action):
"""
Return whether this action can be done at the same time as another action.
:param other_action: The other action to check against, as GameAction object.
:return: True if both actions can be done at the same time, False otherwise, as boolean.
"""
assert(isinstance(other_action, GameAction))
return self._canDoBoth
def isComplete(self):
"""
Return whether this action is complete.
:return: True if the action is complete, False otherwise, as boolean.
"""
return self._completed
def execute(self):
"""
Execute the action. In this case, by writing to the blackboard (if we have one) and
setting the completed flag to True.
:return: None
"""
print("Executing ActionOne")
if self._write_blackboard:
self._write_blackboard('ActionOne Output', 15)
print("Wrote to blackboard: ActionOne Output = 15")
self._completed = True
return None
def getGoalChange(self, goal=None):
"""
Return the goal insistence change associated with this action.
:param goal: The goal to check against, as GameGoal object.
:return: The goal insistence change associated with this action, as int.
"""
assert(isinstance(goal, GameGoal))
if isinstance(goal, GoalOne):
return -GoalInsistence.MEDIUM
else:
return -GoalInsistence.LOW
class ActionTwo(GameAction):
def __init__(self, expiry_time=0, priority=0, read_blackboard=None, write_blackboard=None):
"""
:parameter expiry_time: The time in an arbitrary count-up from zero until the action expires, as int
:parameter priority: The priority of the action. Higher numbers indicate higher priority. As int
:parameter read_blackboard: A function to read from the blackboard, as callable
Signature: read_blackboard(key: str) -> any
:parameter write_blackboard: A function to write to the blackboard, as callable
Signature: write_blackboard(key: str, value: any) -> None
"""
super().__init__(expiry_time, priority, read_blackboard, write_blackboard)
self._canInterrupt = False
self._canDoBoth = False
self._completed=False
def canInterrupt(self):
"""
Return whether this action can interrupt any other action.
:return: True if the action can interrupt any other action, False otherwise, as boolean.
"""
return self._canInterrupt
def canDoBoth(self, other_action):
"""
Return whether this action can be done at the same time as another action.
:param other_action: The other action to check against, as GameAction object.
:return: True if both actions can be done at the same time, False otherwise, as boolean.
"""
assert(isinstance(other_action, GameAction))
return self._canDoBoth
def isComplete(self):
"""
Return whether this action is complete.
:return: True if the action is complete, False otherwise, as boolean.
"""
return self._completed
def execute(self):
"""
Execute the action. In this case, by reading from the blackboard (if we have one) and
setting the completed flag to True.
:return: None
"""
print("Executing ActionTwo")
if self._read_blackboard:
value = self._read_blackboard('ActionOne Output')
print(f"Read from blackboard: ActionOne Output = {value}")
self._completed = True
return None
def getGoalChange(self, goal=None):
"""
Return the goal insistence change associated with this action.
:param goal: The goal to check against, as GameGoal object.
:return: The goal insistence change associated with this action, as int.
"""
assert(isinstance(goal, GameGoal))
if isinstance(goal, GoalTwo):
return -GoalInsistence.MEDIUM
else:
return -GoalInsistence.LOW
# Create the Gob (goal-oriented behavior) object.
gob = Gob()
# Add goals to the Gob.
gob.add_goal(GoalOne('goal_1'))
gob.add_goal(GoalTwo('goal_2'))
# Create actions and add them to the Gob.
act1 = ActionOne(expiry_time=10)
act2 = ActionTwo(expiry_time=10)
gob.add_action(act1)
gob.add_action(act2)
# Create the ActionManager.
mgr = ActionManager()
# Choose the best action to execute.
(bestAct, topGoal) = gob.chooseAction()
bestAct.expiry_time = mgr.currentTime + bestAct.expiry_time # Set the expiry time for the action.
print(f'Chose action with priority {bestAct.priority} to fulfill goal "{topGoal.name}" with insistence {topGoal.getInsistence()}')
# Schedule the best action in the ActionManager.
mgr.scheduleAction(bestAct)
# Output the action manager state.
print(f'Action Manager State before execution:\n{mgr}')
# Execute the action manager, which will activate the scheduled action and execute it
mgr.execute()
# Output the action manager state.
print(f'Action Manager State after first execution:\n{mgr}')
# Execute the action manager again, which will remove the completed action from the active list.
mgr.execute()
# Output the action manager state.
print(f'Action Manager State after second execution:\n{mgr}')
# Create a GameActionCombination and demonstrate its use in the Gob and ActionManager.
combo = GameActionCombination(expiry_time=10, combo_acts=[act1, act2])
gob.add_action(combo)
(bestAct, topGoal) = gob.chooseAction()
bestAct.expiry_time = mgr.currentTime + bestAct.expiry_time # Set the expiry time for the action.
print(f'\nChose action with priority {bestAct.priority} to fulfill goal "{topGoal.name}" with insistence {topGoal.getInsistence()}')
mgr.scheduleAction(bestAct)
print(f'Action Manager State before execution:\n{mgr}')
# Activate the scheduled combination action, and execute both actions in the combo.
mgr.execute()
print(f'Action Manager State after first execution:\n{mgr}')
# Remove the completed combination action from the active list.
mgr.execute()
print(f'Action Manager State after second execution:\n{mgr}')
# Remove the combination action from the Gob's action list, so it doesn't interfere with the rest of the demo,
# since it's insistence change is the same as the sequence action created next.
gob.remove_action(combo)
# Create a GameActionSequence, demonstrate its use in the Gob and ActionManager, and use of the
# blackboard to pass information between actions in a sequence.
seq = GameActionSequence(expiry_time=10)
act1 = ActionOne(expiry_time=10, read_blackboard=seq.readFromBlackBoard, write_blackboard=seq.writeToBlackBoard)
act2 = ActionTwo(expiry_time=10, read_blackboard=seq.readFromBlackBoard, write_blackboard=seq.writeToBlackBoard)
seq.addAction(act1)
seq.addAction(act2)
gob.add_action(seq)
(bestAct, topGoal) = gob.chooseAction()
bestAct.expiry_time = mgr.currentTime + bestAct.expiry_time # Set the expiry time for the action.
print(f'\nChose action with priority {bestAct.priority} to fulfill goal "{topGoal.name}" with insistence {topGoal.getInsistence()}')
mgr.scheduleAction(bestAct)
print(f'Action Manager State before execution:\n{mgr}')
# Activate the scheduled sequence action, and execute the first action in the sequence.
mgr.execute()
print(f'Action Manager State after first execution:\n{mgr}')
# Execute the second action in the sequence.
mgr.execute()
print(f'Action Manager State after second execution:\n{mgr}')
# Remove the completed sequence action from the active list.
mgr.execute()
print(f'Action Manager State after third execution:\n{mgr}')
Demonstration
To run the demonstration, type python -m pyGameAIFoundation.main in a terminal window. Note, that this assumes that the
pyGameAIFoundation package has been installed in your Python environment. The demonstration is essentially the
same as the usage example above.
Unittests
Unittests for the pyGameAIFoundation are in the tests directory, with filenames starting with test_. To run the unittests,
type python -m unittest discover -s ..\..\tests -v in a terminal window in the src\pyGameAIFoundation directory.
License
MIT License. See the LICENSE file for details
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pygameaifoundation-0.1.1.tar.gz.
File metadata
- Download URL: pygameaifoundation-0.1.1.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30100bb5379215038b0bbfc7d466637901e18396465a31ba7cc2cf394e934b2c
|
|
| MD5 |
5c6d21a2bbc17300040843064ef18439
|
|
| BLAKE2b-256 |
4f9418621c41572fd58c14cb2351b42ffbbdf3cd36ff6e344f6420d66116419a
|
Provenance
The following attestation bundles were made for pygameaifoundation-0.1.1.tar.gz:
Publisher:
release.yml on KevinRGeurts/pyGameAIFoundation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygameaifoundation-0.1.1.tar.gz -
Subject digest:
30100bb5379215038b0bbfc7d466637901e18396465a31ba7cc2cf394e934b2c - Sigstore transparency entry: 711169379
- Sigstore integration time:
-
Permalink:
KevinRGeurts/pyGameAIFoundation@3a3ce214445162ec0441970e62adfc7c1fe3278f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/KevinRGeurts
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3a3ce214445162ec0441970e62adfc7c1fe3278f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pygameaifoundation-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pygameaifoundation-0.1.1-py3-none-any.whl
- Upload date:
- Size: 19.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b21b7b14e6df74341dcf418ded3098823c3b3b6db3eba20031b870c02dbd284
|
|
| MD5 |
cbee6bc2615545d3a1a1e03b6ffb3f33
|
|
| BLAKE2b-256 |
7eb2c3189df57527f018c969e18fa63f2b9de1f872c7981f4aa4d0f5c00f1245
|
Provenance
The following attestation bundles were made for pygameaifoundation-0.1.1-py3-none-any.whl:
Publisher:
release.yml on KevinRGeurts/pyGameAIFoundation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygameaifoundation-0.1.1-py3-none-any.whl -
Subject digest:
4b21b7b14e6df74341dcf418ded3098823c3b3b6db3eba20031b870c02dbd284 - Sigstore transparency entry: 711169432
- Sigstore integration time:
-
Permalink:
KevinRGeurts/pyGameAIFoundation@3a3ce214445162ec0441970e62adfc7c1fe3278f -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/KevinRGeurts
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3a3ce214445162ec0441970e62adfc7c1fe3278f -
Trigger Event:
workflow_dispatch
-
Statement type: