Skip to content

Instantly share code, notes, and snippets.

@mkowoods
Created March 30, 2016 20:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkowoods/443bb2aa3355a0e3d4d23daaf0d00b92 to your computer and use it in GitHub Desktop.
Save mkowoods/443bb2aa3355a0e3d4d23daaf0d00b92 to your computer and use it in GitHub Desktop.
# Finite State Machine
# An Example of Finite State Machine Using Classes
# Responsed to: https://www.reddit.com/r/dailyprogrammer/comments/4cb7eh
class FiniteStateMachine:
def __init__(self):
self.states = set([])
self.transitions = {}
self.current_state = None
def set_state(self, state):
self.states.add(state)
def set_states(self, states):
#set a list of states
assert type(states) == type([]), 'states is not a list'
self.states = self.states.union(states)
def set_current_state(self, state):
assert state in self.states, 'state not found in set of current states'
self.current_state = state
def set_transition_function(self, trans_name, trans_dict):
# function that takes as input the current state and returns the state after the transition
# since the mapping is 1 to 1, we use a simple dictionary to represent
self.transitions[trans_name] = trans_dict
def update_trans_function(self, trans_name, prior_state, post_state):
self.transitions[trans_name][prior_state] = post_state
def get_current_state(self):
return self.current_state
def apply_transition(self, trans_name):
next_state = self.transitions[trans_name].get(self.current_state)
# if a state isnt known to the transition function then it stays at it's current state(loops)
if next_state is None:
print 'Transition Ignored: State: %s is not defined for Transition Function: %s'%(self.current_state, trans_name)
next_state = self.current_state
assert next_state in self.states, 'transition funciton returned a state that isnt known'
self.current_state = next_state
if __name__ == "__main__":
GarageStates = ['OPEN', 'CLOSED', 'STOPPED_WHILE_CLOSING', 'STOPPED_WHILE_OPENING', 'OPENING', 'CLOSING']
trans_button_clicked = dict([('OPEN', 'CLOSING'), ('OPENING', 'STOPPED_WHILE_OPENING'), ('STOPPED_WHILE_OPENING', 'CLOSING'),
('CLOSING', 'STOPPED_WHILE_CLOSING'), ('STOPPED_WHILE_CLOSING', 'OPENING'), ('CLOSED', 'OPENING')
])
trans_cycle_complete = dict([('OPENING', 'OPEN'), ('CLOSING', 'CLOSED')])
GarageFSM = FiniteStateMachine()
GarageFSM.set_states(GarageStates)
GarageFSM.set_transition_function('button_clicked', trans_button_clicked)
GarageFSM.set_transition_function('cycle_complete', trans_cycle_complete)
GarageFSM.set_current_state('CLOSED')
for trans in ['button_clicked', 'cycle_complete', 'button_clicked', 'button_clicked', 'button_clicked', 'button_clicked', 'button_clicked', 'cycle_complete']:
print 'Door: '+GarageFSM.get_current_state()
print '> '+trans
GarageFSM.apply_transition(trans)
print 'Door: ' + GarageFSM.get_current_state()
print '###############################################'
#Bonus Challenge
trans_button_clicked = dict(
[('OPEN', 'CLOSING'), ('OPENING', 'STOPPED_WHILE_OPENING'), ('STOPPED_WHILE_OPENING', 'CLOSING'),
('CLOSING', 'STOPPED_WHILE_CLOSING'), ('STOPPED_WHILE_CLOSING', 'OPENING'), ('CLOSED', 'OPENING'),
])
trans_cycle_complete = dict([('OPENING', 'OPEN'), ('CLOSING', 'CLOSED'), ('EMERGENCY_OPENING', 'BLOCKED_OPEN')])
trans_block_detected = dict([('CLOSING', 'EMERGENCY_OPENING'),
('STOPPED_WHILE_OPENING', 'BLOCKED_STOPPED_WHILE_OPENING'),
('STOPPED_WHILE_CLOSING', 'BLOCKED_STOPPED_WHILE_CLOSING'),
('OPEN', 'BLOCKED_OPEN')
])
trans_block_cleared = dict([('BLOCKED_OPEN', 'OPEN'),
('BLOCKED_STOPPED_WHILE_OPENING', 'STOPPED_WHILE_OPENING'),
('BLOCKED_STOPPED_WHILE_CLOSING', 'STOPPED_WHILE_CLOSING')
])
GarageFSM.set_states(['BLOCKED_STOPPED_WHILE_CLOSING', 'BLOCKED_STOPPED_WHILE_OPENING', 'BLOCKED_OPEN', 'EMERGENCY_OPENING'])
GarageFSM.set_transition_function('button_clicked', trans_button_clicked)
GarageFSM.set_transition_function('cycle_complete', trans_cycle_complete)
GarageFSM.set_transition_function('block_detected', trans_block_detected)
GarageFSM.set_transition_function('block_cleared', trans_block_cleared)
GarageFSM.set_current_state('CLOSED')
for trans in ['button_clicked', 'cycle_complete', 'button_clicked', 'block_detected', 'button_clicked',
'cycle_complete', 'button_clicked', 'block_cleared', 'button_clicked','cycle_complete']:
print 'Door: ' + GarageFSM.get_current_state()
print '> ' + trans
GarageFSM.apply_transition(trans)
print 'Door: ' + GarageFSM.get_current_state()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment