Tactical Control Group

This is (mostly) automagic documentation for our ongoing Python work. What does Tactical Control actually do? Somebody needs to write a description for that...

Documentation for FSM Examples

Finite State Machines with some extra goodies attached.

Generic FSM Modules

Modules in this section are not specific to WestWorld2; they can be used anywhere we need an FSM.


base_entity.py:

Module for defining managing game-type entities.

Use the BaseEntity class for agents that need a unique ID as well as periodic updating and messaging functionality. The EntityManager class provides a simple interface for automatic management.

Messages are sent via an instance of the MessageDispatcher class. This works with an EntityManager in order to serve as a kind of post office. Both immediate and delayed messages are possible; see the class description.

class base_entity.BaseEntity(myID, postoffice)

Abstract Base Class for objects with an ID, update, and messaging.

Parameters:
  • myID (int) – The unique ID assigned to this entity.
  • postoffice (MessageDispatcher) – Where this entity will send its messages.
Raises:

ValueError – If the requested ID is invalid.

Notes

Because of how messaging is implemented, each entity needs a unique ID. We use a private class variable to make sure that ID’s are not repeated. Since ID’s aren’t recycled, we can’t accidentally send a message or otherwise refer to an entity that is no longer valid.

get_id()

Returns the ID of this entity.

update()

Update method that will be called each step This must be implemented by subclasses.

receive_msg(message)

Message handler; must be implemented my subclasses.

Parameters:message (tuple) – A message constructed using the telegram() function.
class base_entity.EntityManager

Manager class for objects of type BaseEntity

register(entity)

Add an instance of BaseEntity to this manager.

Parameters:entity (BaseEntity) – An entity that has been instantiated outside of this class.
remove(entity)

Remove an instance of BaseEntity from this manager.

Notes

Since BaseEntity’s are instantiated/deleted outside of this class, removing only affects this manager’s behavior. This function checks whether entity has the correct type, so deleting entity before removing it from the manager shouldn’t be an issue.

get_entity_from_id(ent_id)

Returns an entity object from its ID.

Returns:The entity corresponding to ent_id. If this ID isn’t registered, returns None.
Return type:BaseEntity
update()

Calls the update() method of all registered entities.

Note: The order in which entities are called in not known.

start_all_fsms()

Starts the FSM for each entity that has one.

class base_entity.MessageDispatcher(clock_now, ent_mgr)

Class for posting/handling messages between entities.

Parameters:
  • clock_now (function()) – A function that returns a numerical value. This is used to represent the current time to control delivery of delayed messages.
  • ent_mgr (EntityManager) – Used by this class to lookup an entity, given its ID.
discharge(receiver, message)

Passes a message to a given recipient.

post_msg(delay, send_id, rec_id, msg_type, extra=None)

Add a message to the queue for immediate or delayed dispatch.

dispatch_delayed()

Dispatches messages from the delayed queue.


state_machine.py

Module containing basic FSM functionality.

All states should be derived from the State class, see its documentation.

Use STATE_NONE as a concrete null state. We need only a single instance.

An instance of BaseEntity can be given FSM functionality as follows:

  • fsm = StateMachine(entity)
  • fsm.set_state(current, global, previous), the last two are optional
  • entity.fsm = fsm
  • In entity’s update() method, call self.fsm.update()

In entity’s receive_msg() method, calling entity.fsm.handle_msg(message) will allow the FSM to route messages to the appropriate state logic: first to the current state, then to the global state.

class state_machine.State

Base class for all states.

States derived from this base class should override the methods below, though all of them are optional. Each method takes a parameter, agent, which is the BaseEntity that is using that state. This allows multiple entities to reuse the same state logic.

enter(agent)

Code to execute immediately when changing to this state.

execute(agent)

Code to execute each time this state is executed.

leave(agent)

Code to execute just before changing from this state.

on_msg(agent, message)

Code to execute when a message is received.

Note

When overriding this method, we need to return a boolean that indicates if the message was succesfully handled. The messaging functions use this boolean to redirect the message elsewhere if a given state is unable to handle it.

state_machine.STATE_NONE = <state_machine.State object>

Use this as a concrete null state; we need only a single instance.

class state_machine.StateMachine(owner)

Finite State Machine with messaging capability.

After instantiating a new StateMachine, use the set_state() method below in order to explicity initialize the states. Otherwise, this FSM will sit around and do nothing on update.

Parameters:owner (BaseEntity) – The entity using this instance of the FSM.
set_state(cur, glo=None, pre=None)

Manually set owner’s states without triggering state change logic.

Parameters:
  • cur (State) – Current State of the FSM. Use NullState here if you don’t need to explictly set an actual State.
  • glo (State) – Global State (executed each update) of the FSM.
  • pre (State) – Previous State (used by revert_state) of the FSM. Defaults to NullState if not specified or invalid.
start()

Start the FSM by executing global & current state’s enter() methods.

Note

This is an attempt to fix the issue of BaseEntities not having access to messaging during their __init__() functions. This calls the enter() methods of the global state first, then the FSM’s current state.

update()

Execute the owner’s global state (if any), then current state.

change_state(newstate)

Switches owner to a new state, calling leave/enter methods.

Parameters:
  • newstate (State) – The FSM will switch to this state.
  • Note (Both the current and new states must be valid, otherwise nothing) –
  • happen and we'll stay in the current state. (will) –
revert_state()

Reverts owner to its previous state; useful for state blips.

handle_msg(message)

Used by the FSM to route received messages.

The message is first passed to the current state, which tries to handle it. If the current state fails to do so, the message is then passed to the global state, if one exists.

Parameters:message (tuple) – A message constructed using the telegram() function.
Returns:True if the message was handled by either the current or global state; False otherwise.
Return type:bool

Westworld2 Specifics

Example usage of the Generic FSM Modules.


Sample Output

  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Found me a gold nugget!
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 3 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Found me a gold nugget!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 6 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Found me a gold nugget!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Now depositin’ 4 gold...
  • Miner Bob : Saved myself 10 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Day’s a finished, headin’ on home!
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Wife Elsa : Heading back to the kitchen...
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Wife Elsa : Stew’s ready, come an’ git it!
  • Miner Bob : I hears ya’, lil’ lady...
  • Wife Elsa : Headin’ to the dinner table...
  • Miner Bob : That’s some might fine stew...thank ya much, Elsa!
  • Miner Bob : Now where was I...?
  • Wife Elsa : Eatin’ the stew...I outdone myself this time.
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Wife Elsa : Done got me a message, oh my!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Done restin’ fer now, back to work!
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 13 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Day’s a finished, headin’ on home!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Done restin’ fer now, back to work!
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Wrassalin’ with dinner...
  • Wife Elsa : Stew’s ready, come an’ git it!
  • Miner Bob : Done got me a message! Yeehaw!
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Wife Elsa : Headin’ to the dinner table...
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 16 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Day’s a finished, headin’ on home!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Wife Elsa : Headin’ to the dinner table...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Eatin’ the stew...I outdone myself this time.
  • Wife Elsa : Housework ain’t gonna do itself!
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Done restin’ fer now, back to work!
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Wrassalin’ with dinner...
  • Wife Elsa : Stew’s ready, come an’ git it!
  • Miner Bob : Done got me a message! Yeehaw!
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Eatin’ the stew...I outdone myself this time.
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 19 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Day’s a finished, headin’ on home!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Done restin’ fer now, back to work!
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Wrassalin’ with dinner...
  • Wife Elsa : Stew’s ready, come an’ git it!
  • Miner Bob : Done got me a message! Yeehaw!
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Wife Elsa : Headin’ to the dinner table...
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Eatin’ the stew...I outdone myself this time.
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Miner Bob : Keep on a-diggin’...
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me a gold nugget!
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Now depositin’ 4 gold...
  • Miner Bob : Saved myself 23 gold...soon’ll be rich!
  • Miner Bob : Leavin’ the bank...
  • Miner Bob : Day’s a finished, headin’ on home!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Wife Elsa : Heading back to the kitchen...
  • Wife Elsa : Gonna rustle up some mighty fine stew!
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Miner Bob : Zzzzzz....
  • Wife Elsa : Wrassalin’ with dinner...
  • Wife Elsa : Stew’s ready, come an’ git it!
  • Miner Bob : I hears ya’, lil’ lady...
  • Wife Elsa : Headin’ to the dinner table...
  • Miner Bob : That’s some might fine stew...thank ya much, Elsa!
  • Miner Bob : Now where was I...?
  • Wife Elsa : Eatin’ the stew...I outdone myself this time.
  • Wife Elsa : Housework ain’t gonna do itself!
  • Wife Elsa : Done got me a message, oh my!
  • Miner Bob : Done restin’ fer now, back to work!
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me two nuggets, whaddaya know!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to the saloon fer a drink...
  • Wife Elsa : Thar’s a goat in mah yard!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Nom nom flowers
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Wife Elsa : Shoo, ya silly goat!
  • Goat : Scampers away
  • Headin’ on home...
  • Wife Elsa : Housework ain’t gonna do itself!
  • Miner Bob : Havin’ a whiskey...mighty refreshin’!
  • Miner Bob : Leavin’ the saloon fer now...
  • Miner Bob : Walkin’ to the gold mine...
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Found me a gold nugget!
  • Miner Bob : Done diggin’ fer now.
  • Miner Bob : Headin’ to bank, yessiree!
  • Wife Elsa : Workin’ round the house...tra-la-lah-la-lah...
  • Miner Bob : Now depositin’ 3 gold...
  • Miner Bob : Saved myself 26 gold...soon’ll be rich!
  • Miner Bob : Whee, doggy! A winner is y’all!
  • Elapsed time: 79 clock ticks.

Module dependencies

Autogenerated using pyreverse

_images/packages_FSM_Examples.png

UML Class Diagram

Autogenerated using pyreverse

_images/classes_FSM_Examples.png

gamedata.py:

Game-wide constants.

Game Entities
  • BOB: Miner Bob, Elsa’s husband
  • ELSA: Wife Elsa, scourge of wandering goats
Locations
  • SHACK: Bob and Elsa’s humble home
  • MINE: Gold mine. Dig for nuggets here!
  • BANK: A bank, duh. Deposit nuggets here!
  • SALOON: Quench yer thirst here!
  • YARD: Frequently invaded by flower-eating goats!
Message Types
  • MINER_HOME: Bob sends this when he comes home from digging.
  • STEW_READY: Elsa sends this when she’s finished cooking.
exception gamedata.GameOver

Raise this exception to end the game.


ent_miner.py:

Miner Entity using simple FSM functionality.

class ent_miner.Miner(*args)

Miner Bob.

Note: The constructor doesn’t take any actual args, but this syntax is needed to call the __init__ method of the superclass. I’m not sure that we need to do so here, but it will be a useful reminder for later.

update()

Increases thirst and updates the FSM logic.

change_location(newlocation)

Move to another location

Location constants are enumerated in gamedata.py

change_gold(amount)

Add/subtract the amount of gold currently carried

Parameters:amount (int) – Amount of gold to add (or subtract, if negative)
pockets_full()

Queries whether this entity is carrying enough gold.

add_fatigue(amount=1)

Increases the current fatigue of this entity.

remove_fatigue(amount=1)

Remove fatigue from this entity, but not below zero.

is_thirsty()

Queries if this entity has too much current thirst.

remove_thirst(amount)

Remove thirst from this entity, but not below zero.

work_done()

Returns True if more than 10 gold in the bank.

Note

Fix this! Once there is 10 gold or more in the bank, the Miner will go home after each bank deposit. We don’t want that.

class ent_miner.GlobalMinerState

Global state that just handles message.

Prints that a message was received, with no further details.

class ent_miner.DigInMine

Go to the mine and dig until pockets full or thirsty.

State Transitions:

  • When pockets are full -> DepositInBank
  • When thirsty -> DrinkAtSaloon
class ent_miner.DepositInBank

Go to the bank and deposit all carried gold.

State Transitions:

  • If more than 25 gold in the bank -> GameOver
  • If work_done (enough money in bank) -> GoHomeAndRest
  • Otherwise -> DigInMine
class ent_miner.DrinkAtSaloon

Go to the saloon and drink until thirst is quenched

State Transitions:

  • When no longer thirsty -> revert to previous
class ent_miner.GoHomeAndRest

Go home and rest.

When Miner Bob enters this state, he sends Elsa a message to start cooking the stew. He’s apparently impatient or a workaholic, because he will go back to the mine once fully rested, even if he’s not eaten yet. Poor Elsa!

State Transitions:

  • Once fully rested -> DigInMine
  • If stew is ready and is still in SHACK -> MinerEatStew
class ent_miner.MinerEatStew

Eat that tasty stew, and thank yer lovely wife!

Food removes fatigue, of course.

State Transitions:

  • After a single execute() to eat stew -> revert to previous

ent_wife.py:

Wife Entity using simple FSM functionality

class ent_wife.Wife(*args)

Wife Elsa, scourge of the goats.

Note: The constructor doesn’t take any actual args, but this syntax is needed to call the __init__ method of the superclass. I’m not sure that we need to do so here, but it will be a useful reminder for later.

update()

Updates the FSM logic, and nothing else.

class ent_wife.GlobalWifeState

Wife State: Global state that handles messages and chases goats!

State Transitions (these change the current state, not the global one):

  • Goat in yard -> ChaseGoat
  • on_msg MINER_HOME -> Cook Stew
class ent_wife.DoHouseWork

Old West misogyny, yeehaw!

Note

Elsa is apparently a lot tougher than her husband, since she never gets tired or thirsty! We should probably give her some more interesting things to do...a good exercise in FSM design/coding!

This state has no transitions; those are handled by GlobalWifeState.

class ent_wife.CookStew

More bro-gramming at it’s finest, but the code is quite involved.

On entering this state, Elsa posts a delayed STEW_READY message so that she knows the cooking is done. Once she receives this, she then sends an immediate STEW_READY to Bob before sitting down to eat herself.

State Transitions:

  • on_msg STEW_READY -> WifeEatStew
class ent_wife.WifeEatStew

Eat that tasty stew!

State Transitions:

  • After one execute() to eat stew -> DoHouseWork
class ent_wife.ChaseGoat

Head to the yard and shoo that goat!

Goats are stubborn critters, so there’s a random chance that Elsa fails to shoo the goat. But she’ll keep at it until the job’s done!

Goats also demand undivided attention, but Elsa has a good memory. Any message received by this state will be forwarded to Elsa in the next update() cycle. This means that if Bob comes home whilst Elsa’s chasing a goat, she’ll still receive the MINER_HOME message when she’s done.

State Transitions:

  • Successfully shoos the goat -> revert to previous

Documentation for Vector-Based Code

Homegrown vector code for use in Python.

Generic Vector Code

For handling math-type vectors in Python.


point2d.py

A Two-Dimensional Point/Vector Class

There are surely much better implementations of this sort of thing, for various definitions of ‘better.’ This module is designed to by easily readable and portable, without having to fuss with installation/importing of modules such as numpy that would probably perform better.

class point2d.Point2d(x=0, y=0)

Creates a 2d vector, defaulting to <0,0>.

Parameters:
  • x (float) – x-coordinate (defaults to 0).
  • y (float) – y-coordinate (defaults to 0).
__neg__()

Negates each entry; overrides unary - operator.

Example

>>> a = Point2d(1,-2)
>>> print(-a)
Point2d: <-1.000000, 2.000000>
__add__(term)

Coordinatewise addition; overrides the + operator.

Example

>>> a = Point2d(1,-2)
>>> b = Point2d(3,5)
>>> print(a+b)
Point2d: <4.000000, 3.000000>
__sub__(term)

Coordinatewise subtraction; overrides the - operator.

Example

>>> a = Point2d(1,-2)
>>> b = Point2d(3,5)
>>> print(a-b)
Point2d: <-2.000000, -7.000000>
__mul__(term)

Dot product; overrides the * operator.

Example

>>> a = Point2d(1,-2)
>>> b = Point2d(3,5)
>>> a*b
-7.0
__getitem__(index)

Vector components; indexed starting at 0.

Example

>>> a = Point2d(1,-2)
>>> a[0]
1.0
>>> a[1]
-2.0
scale(scalar)

Get a scaled version of this vector.

Example

>>> a = Point2d(1,-2)
>>> print(a.scale(-2))
Point2d: <-2.000000, 4.000000>
norm()

Get the norm (length) of this vector.

Example

>>> a = Point2d(1,-2)
>>> a.norm()
2.23606797749979
sqnorm()

Get the squared norm (length) of this vector.

Example

>>> a = Point2d(1,-2)
>>> a.sqnorm()
5.0
unit()

Get a unit vector in the same direction as this one.

Note

Be aware of round-off errors; see the example below.

Example

>>> a = Point2d(1,-2)
>>> print(a.unit())
Point2d: <0.447214, -0.894427>
>>> a.unit().norm()
0.9999999999999999
normalize()

Rescale this vector to have length 1.

Note

Be aware of round-off errors; see the example below.

Example

>>> a = Point2d(1,-2)
>>> a.normalize()
>>> print(a)
Point2d: <0.447214, -0.894427>
>>> a.norm()
0.9999999999999999
truncate(maxlength)

Rescale this vector if needed so its length is not too large.

Parameters:maxlength (float) – Upper limit on the length. If the current length exceeds this, the vector will be rescaled.
Returns:True if rescaling was done, False otherwise.
Return type:bool

Example

>>> a = Point2d(1,-2)
>>> a.truncate(1.0)
True
>>> a = Point2d(-1,2)
>>> a.truncate(5.0)
False
>>> print(a)
Point2d: <-1.000000, 2.000000>
>>> a.truncate(1.0)
True
>>> print(a)
Point2d: <-0.447214, 0.894427>
angle()

Get the polar angle of this vector in radians.

Example

>>> a = Point2d(1,-2)
>>> a.angle()
-1.1071487177940904

Notes

This is implemeted using acos. Perhaps atan gives better performance?

__div__(direction)

Length of an orthogonal projection; overrides the / operator.

Parameters:direction (Point2d) – The vector we project onto; not required to be a unit vector.
Returns:The length of the projection vector.
Return type:float

Notes

Returns the scalar q such that self = q*v2 + v3, where v2 is in the span of direction and v2 and v3 are orthogonal. This is algebraically identical to exact division (/).

If you want the result as a vector, use Point2d.proj(direction) instead.

Examples

>>> a = Point2d(2,2)
>>> b = Point2d(3,0)
>>> a/b
2.0
>>> b/a
2.1213203435596424
proj(direction)

Get the orthogonal projection of this vector onto another.

Parameters:direction (Point2d) – The vector we project onto; not required to be a unit vector.
Returns:The unique vector v2 such that self = q*v2 + v3, where v2 is in the span of direction and v2 and v3 are orthogonal.
Return type:Point2d

Example

>>> a = Point2d(2,4)
>>> b = Point2d(3,-2)
>>> print(a.proj(b))
Point2d: <-0.461538, 0.307692>
>>> print(b.proj(a))
Point2d: <-0.200000, -0.400000>

Notes

If you want both v2 and v3, use Point2d.resolve(direction) instead.

resolve(direction)

Orthogonal decomposition of this vector in a given direction.

Parameters:direction (Point2d) – The vector we project onto; not required to be a unit vector.
Returns:(v2,v3) such that self = q*v2 + v3, where v2 is in the span of direction and v2 and v3 are orthogonal.
Return type:(Point2d, Point2d)

Example

>>> a = Point2d(2,2)
>>> b = Point2d(3,0)
>>> print(a.resolve(b)[0])
Point2d: <-0.461538, 0.307692>
>>> print(a.resolve(b)[1])
Point2d: <2.461538, 3.692308>
>>> print(a.resolve(b)[0]+a.resolve(b)[1])
Point2d: <2.000000, 4.000000>
left_normal()

Returns the left-facing normal of this vector

Example

>>> a = Point2d(1, -2)
>>> print a.left_normal()
Point2d: <2.000000, 1.000000>
__setitem__(index, value)

Allows a value to be assigned to each vector components; indexed starting at 0

Example

>>> a = Point2d(1, -2)
>>> print a
Point2d: <1.000000, -2.000000>
>>> a[0] = 3
>>> a[1] = 5
>>> print a
Point2d: <3.000000, 5.000000>

Documentation for Graph-Theoretic Code

Homegrown graph theory code for use in Python.

Generic Graph Theory Code

Graph-theoretic operations in Python.


base_graph.py

Module for various type of graph nodes/edges. WORK IN PROGRESS!

base_graph.INVALID_NODE_ID = -1

Any reference to this index is treated as being a nonexistant node.

class base_graph.BaseGraphNode(node_id, **kwargs)

Base class for various types of graph nodes.

Parameters:
  • node_id (int) – ID to assign this node, to allow consistency with external information.
  • kwargs (any, optional) – Additional attributes can be set using keyword arguments. Each key (except node_id) sets an instance variable with the same name. There is no error-checking in the base class, but subclasses may override this.

Note

Subclasses should call the base __init__() method (via super) to set the node ID and any extra keyword arguments. The base class keeps a master directory of nodes by id, which can be accessed using the module function get_node(node_id).

base_graph.get_node(node_id)

A handle to the node with the given id; None for invalid nodes.

class base_graph.EasyGraphNode(node_id, **kwargs)

A BaseGraphNode with anonymous directed edges.

Adjacency is stored locally per node, using a dictionary keyed by node ID, Entries can then represent edge information (weight, label, etc.), but there is no way to access edges independently. To modify adjacency, use either the make_edges() or remove_edges() method on the source node.

Parameters:
  • node_id (int) – ID to assign this node, to allow consistency with external information.
  • kwargs (any, optional) – Additional attributes can be set using keyword arguments. Each key (except node_id) sets an instance variable with the same name.
get_id()

Returns the ID of this node.

ignore_me()

Sets this node to be treated as temporarily inactive.

Note

After calling this, existing references to this node will remain valid, but any future queries to node_from_id[] will return None. This gives the ability to temporarily ignore nodes without the overhead of deleting them. Provided that we keep an external reference, we can reactivate this node later, using make_valid() below.

unignore_me()

Restore this node to being treated as active.

Note

After calling this, any information about this node (including edges to/from adjancent nodes) that existed before make_invalid() will once again be available.

make_edges(neighbor, label=1)

Create edge(s) from this node, with optional weight (default 1).

Parameters:
  • neighbor (int or list of int) – The ID of the node to connect to.
  • label (object or list of objects, optional) – The label/weight information for the edge(s) (default = 1). If a single label is given, all neighbors get that label. If a list is given, it must have the same length as neighbor.

Note

This will overwrite any previous edge to the given neighbor(s). This does not check if neighbor(s) is/are currently active or valid, so we can create edges to node id’s that do not yet exist.

remove_edges(neighbor)

Remove any existing edges to the given neighbor(s).

Parameters:neighbor (int or list of int) – The ID of the nodes to remove edges to.
neighbor_ids()

The set of IDs of active nodes adjacent to this one.

neighbor_nodes()

The set of active nodes adjacent to this one.

edges_from()

A dictionary of edges from this node, keyed by neighbor ID. Inactive neighbors are ignored.

base_gridgraph.py

Basic GridGraph class. Demo uses Pygame for rendering.

class base_gridgraph.GridGraph(cols=2, rows=2, dx=1.0, dy=1.0)

A regular rectangular grid with Manhattan/diagonal neighborhoods.

Parameters:
  • cols (int) – Number of node columns (in the horizontal dimension).
  • rows (int) – Number of node rows (in the vertical dimension).
  • dx (float) – Edge weight between horizontally adjacent nodes.
  • dy (float) – Edge weight between vertically adjacent nodes.
is_node(node)

Check for a valid node (even if it’s inactive).

is_not_inactive((x, y))

Check for an active node (does not check for validity).

Note

For performance reasons, this simply checks if the node with grid coordinates (x,y) is in the grid’s inactive list.

edge_cost(node0, node1)

Get the edge cost between two nodes. :returns: float

Return type:The edge cost, or INF if the nodes are not adjacent.
Raises:IndexError (If either node is invalid.) –
active_neighbors(node)

Get a list of active neighbors for the given node.

Parameters:node (2-tuple of int) – Grid coordinates of the given node.

Note

For performance reasons, this does not check if node is valid.

Documentation for BOID/Vehicle Code

Still working on this...

BOID/Vehicle Code

Still working on this section...


vehicle2d.py

Indices and tables

If you need to convince yourself of the awesome power of Sphinx autodocs, look at the (autogenerated) links below: