How To Build a Finite State Machine (FSM) with Swift

Yes, I admit, I ♥ Swift.

Currently, I'm working on a game. For the AI of this game, I decided to use Finite State Machines (FSMs). This is a technique I like and know very well, but rather from hardware design languages like VHDL/Verilog. Making FSMs in e.g. C++ feels sometimes a bit awkward, because you have to use if-else-if constructs. This is because one usually wants to make a decision on both, the old state and the next one. Yes, one could use switch and for instance a union or otherwise combined numbers, but to me this feels to much like hacking it together. Gladly, Swift makes provided us a cool enum with which I'm going to show you how much fun FSMs in Swift can be.

First, we need two protocols. We could do this in one delegate but IMO two separate ones provide more control. So, first there has to be a protocol which enables us retrieving the next state and comparing states, e.g.:

protocol FSMStatesProtocol  
{
    func getNextState() -> FSMStatesProtocol
    func equalsState(state: FSMStatesProtocol) -> Bool
}

The other protocol will form a simple delegate which is later used for actually making the switch:

protocol FSMDelegateProtocol  
{
    func switchState(oldState oldState: FSMStatesProtocol, newState: FSMStatesProtocol) -> Bool
}

Now comes the definition of the state machine itself. Code first, explanations will follow:

class StateMachine : NSObject  
{
    private var state : FSMStatesProtocol
    var delegate : FSMDelegateProtocol?

    init(initialState: FSMStatesProtocol)
    {
        state = initialState
        super.init()
    }

    func updateFSM()
    {
        let newState = state.getNextState()
        if state.equalsState(newState) { return }

        if let switcher = delegate
        {
            if switcher.switchState(oldState: state, newState: newState)
            {
                state = newState
            }
        }
    }
}

As one can see, the state machine class contains variables for both protocols defined before. Besides initializing state with some initial state there is nothing special in here. However, the fancyness comes with updateFSM which does the following:

  1. Receive a possible new state to switch to by calling the respective method from the protocol.
  2. Checking whether the states are equal, in which case nothing more needs to be done.
  3. Calling the delegate to actually make the switch, and
  4. if the switch was successful, save the new state.

Easy and straightforward, isn't it? Now we come to the actual use of the state machine. I'm going to demonstrate this with the FigureAI class.

class FigureAI : FSMDelegateProtocol  
{
    enum FigureStates : FSMStatesProtocol
    {
        case Sitting, Walking, Standing

        func equalsState(state: FSMStatesProtocol) -> Bool
        {
            return self == (state as! FigureStates)
        }

        func getNextState() -> FSMStatesProtocol
        {
            switch self
            {
                case Sitting  : return Standing
                case Walking  : return Standing
                case Standing : return Sitting
            }
        }
    }

    func switchState(oldState oldState: FSMStatesProtocol, newState: FSMStatesProtocol) -> Bool
    {
        let oldState = oldState as! FigureStates
        let newState = newState as! FigureStates

        switch (oldState, newState)
        {
            case (.Sitting, .Standing):
                makeFigureStandUp()
                return true

            case (.Standing, .Sitting):
                makeFigureSitDown()
                return true

            // More cases

            default: return false
        }
    }   
}

Again, straightforward implemention, no black magic™. The class in detail:

FigureStates implements an enum which conforms to the previously defined FSMStatesProtocol. For compliance, it has to implement equalsState and getNextState. Of course, in equalsState, we have to use a cast from FSMStatesProtocol to FigureStates. Since this case won't fail, we used as! instead of as? for casting. getNextState is fairly easy, it simply returns a new state. In a more advanced implementation, one could use e.g. statistics or the like to make it more AI-like.

The best comes for last! switchState is the function which does the magic. Here, we use switch (oldState, newState) and decide what to do. E.g. if the figure is sitting and the new state is standing, we have to make it stand up. The case (.Sitting, .Standing) covers that part. The same goes for standing to sitting. You get the idea.

This particular last part is, what would lead you to many if-else-if statements in C or C++ or any other language which does not provide this enum fancy.

Happy finite switching!

Note: this actually has become a part 2 with an improved version of the state machine: How To Build a Finite State Machine (FSM) with Swift (Pt. 2)