Finite State Automata

Finite State Automata are state machines. They exist in some state until some percept (input) comes along to trigger them to move to another state. As we saw with the locking mechanism, the correct number transitions the state to the next state. The incorrect number resets it back to the beginning.

The goal of this exercise is to model a state machine. This means defining a couple states (3-4 hopefully) and the transitions between them. Then, you should have a function which should handle these transitions. Finally, you should test the transitions with a series of percepts/inputs. I have demonstrated below with a Bunny FSA

Bunny FSA

First, I plan out my Bunny FSA.

What are the states

  • state1 -> bunny is hungry
  • state2 -> bunny is content
  • state3 -> bunny is destroying

What are the transitions between the states

  • state1 -> state2 when fed
  • state2 -> state3 when ignored
  • state3 -> state2 when spoiled
  • state2 -> state1 when time passes

In [7]:
class Bunny:
    def __init__(self):
        self.hungry = False
        self.angry = False

    def feed(self):
        self.hungry = False
    
    def time_passes(self):
        self.hungry = True
        self.angry = False
    
    def get_angry(self):
        self.angry = True
    
    def get_spoiled(self):
        self.angry = False
    
    def user_perceive(self):
        something = input("Give me a percept: ")
        self.perceive(something)
    
    def fancy_perceive(self, percept, x=8):
        all_funcs = {"feed": self.feed,
                     "time": self.time_passes}
    
        
    
    def perceive(self, percept):
        """ see the world, change the state """
        print("Euclid is experiencing {}".format(percept))
        if percept == "feed":
            self.feed()
        elif percept == "time":
            self.time_passes()
        elif percept == "ignore":
            self.get_angry()
        elif percept == "spoiled":
            self.get_spoiled()
        else:
            raise NotImplementedError
        
            
    def act(self):
        """ see the state, change the world """
        pass

    
    def get_state(self):
        if self.hungry:
            return "state1<hungry>"
        elif self.angry:
            return "state3<angry>"
        else:
            return "state2<content>"
    
    def report(self):
        print("Euclid is {}".format(self.get_state()))

In [11]:
euclid = Bunny()
kitchendoor = Door()
print("Initial state")
euclid.report()
percept1 = {"type": "sound", "values": []}
percepts = ['time', 'time', 'ignore', 'feed', 'spoiled']
for percept in percepts:
    print("{:^30}".format("~-"*10))
    euclid.perceive(percept)
    euclid.report()


Initial state
Euclid is state2<content>
     ~-~-~-~-~-~-~-~-~-~-     
Euclid is experiencing time
Euclid is state1<hungry>
     ~-~-~-~-~-~-~-~-~-~-     
Euclid is experiencing time
Euclid is state1<hungry>
     ~-~-~-~-~-~-~-~-~-~-     
Euclid is experiencing ignore
Euclid is state1<hungry>
     ~-~-~-~-~-~-~-~-~-~-     
Euclid is experiencing feed
Euclid is state3<angry>
     ~-~-~-~-~-~-~-~-~-~-     
Euclid is experiencing spoiled
Euclid is state2<content>