Featured image of post Finite State Machines-FSM Explained

Finite State Machines-FSM Explained

Code Examples in Go, Python, C#, and C++

Finite State Machines, History, Understanding How They Work, and Code Examples in Go, Python, C#, and C++


A Brief History of FSMs

Finite state machines have been around longer than your grandpa’s first calculator. The concept was formalized by Warren McCulloch and Walter Pitts in 1943 when they described neural networks using logic gates. Later, the idea of state machines was expanded by John Myhill and Raymond Moore, leading to what we now call Mealy and Moore Machines.

Smart people figured out that a system could have different states and transition between them based on inputs. And here we are, still using that idea to control robots, games, and—most importantly—vending machines.


Understanding How FSMs Work

An FSM consists of:

  1. States: The different conditions a system can be in.
  2. Transitions: Rules for moving from one state to another.
  3. Inputs: Events that trigger transitions.
  4. Outputs: Actions performed when entering, exiting, or being in a state.

Imagine a turnstile at a subway station:

  • Locked state: If you insert a coin, it transitions to Unlocked.
  • Unlocked state: If you push, it transitions back to Locked.

Boom! That’s a finite state machine. Simple, right? Now let’s look at some code!


Code Examples

Go Implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
    "fmt"
)

type State string

const (
    Locked   State = "Locked"
    Unlocked State = "Unlocked"
)

type Turnstile struct {
    state State
}

func (t *Turnstile) InsertCoin() {
    if t.state == Locked {
        fmt.Println("Coin inserted. Unlocking...")
        t.state = Unlocked
    } else {
        fmt.Println("Already unlocked! Just push!")
    }
}

func (t *Turnstile) Push() {
    if t.state == Unlocked {
        fmt.Println("Pushed. Locking...")
        t.state = Locked
    } else {
        fmt.Println("It's locked! Insert a coin first.")
    }
}

func main() {
    t := &Turnstile{state: Locked}
    t.InsertCoin()
    t.Push()
    t.Push()
}

Python Implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Turnstile:
    def __init__(self):
        self.state = "Locked"

    def insert_coin(self):
        if self.state == "Locked":
            print("Coin inserted. Unlocking...")
            self.state = "Unlocked"
        else:
            print("Already unlocked! Just push!")

    def push(self):
        if self.state == "Unlocked":
            print("Pushed. Locking...")
            self.state = "Locked"
        else:
            print("It's locked! Insert a coin first.")

# Example usage
t = Turnstile()
t.insert_coin()
t.push()
t.push()

C# Implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;

class Turnstile
{
    private string state = "Locked";

    public void InsertCoin()
    {
        if (state == "Locked")
        {
            Console.WriteLine("Coin inserted. Unlocking...");
            state = "Unlocked";
        }
        else
        {
            Console.WriteLine("Already unlocked! Just push!");
        }
    }

    public void Push()
    {
        if (state == "Unlocked")
        {
            Console.WriteLine("Pushed. Locking...");
            state = "Locked";
        }
        else
        {
            Console.WriteLine("It's locked! Insert a coin first.");
        }
    }
}

class Program
{
    static void Main()
    {
        Turnstile t = new Turnstile();
        t.InsertCoin();
        t.Push();
        t.Push();
    }
}

C++ Implementation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>

class Turnstile {
private:
    std::string state = "Locked";

public:
    void insertCoin() {
        if (state == "Locked") {
            std::cout << "Coin inserted. Unlocking..." << std::endl;
            state = "Unlocked";
        } else {
            std::cout << "Already unlocked! Just push!" << std::endl;
        }
    }

    void push() {
        if (state == "Unlocked") {
            std::cout << "Pushed. Locking..." << std::endl;
            state = "Locked";
        } else {
            std::cout << "It's locked! Insert a coin first." << std::endl;
        }
    }
};

int main() {
    Turnstile t;
    t.insertCoin();
    t.push();
    t.push();
    return 0;
}

Conclusion

Finite state machines are incredibly useful and appear in more places than you might think. Whether it’s controlling UI flows, video game characters, or vending machines (the true MVPs of life), FSMs keep things organized and predictable.

So go forth and implement FSMs in your projects! And if nothing else, you can now impress your friends by explaining why the turnstile at the subway works the way it does.


Ideas for Further Exploration

  • Implement FSMs for a simple game AI.
  • Use FSMs in a web application to handle user states.
  • Simulate a real-world vending machine with an FSM.
  • Implement a state machine in Rust or Java.

References