Created
March 30, 2016 20:52
-
-
Save mkowoods/443bb2aa3355a0e3d4d23daaf0d00b92 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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