ess / LuaFSM

Finite State Machine library for Lua

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

A design pattern for doing finite state machines (FSMs) in Lua
==============================================================

Based on a very appreciated contribution of Luiz Henrique de Figueiredo
Original code from http://lua-users.org/wiki/FiniteStateMachine

The FSM is described with: old_state, event, new_state and action.
One easy way to do this in Lua would be to create a table in exactly 
the form above:

yourStateTransitionTable = { 
	{state1, event1, state2, action1},
	{state1, event2, state3, action2},
	...
}

The function FSM takes the simple syntax above and creates tables 
for (state, event) pairs with fields (action, new):

function FSM(yourStateTransitionTable)
  local stt = {}
  for _,v in ipairs(t) do
    local old, event, new, action = v[1], v[2], v[3], v[4]
    if stt[old] == nil then a[old] = {} end
    stt[old][event] = {new = new, action = action}
  end
  return stt
end

Note that this scheme works for states and events of any type: number, 
string, functions, tables, anything. Such is the power of associate arrays.

However, the double array stt[old][event] caused a problem for event = nil
Instead a single array is used, constructed as stt[state .. SEPARATOR .. event]
Where SEPARATOR is a constant and defined as '.'

Three special state transitions are added to the original code:
- any state but a specific event
- any event but a specific state
- unknown state-event combination to be used for exception handling

The any state and event are defined by the ANY constant, defined as '*' 
The unknown state-event is defined as the combination of ANY.ANY (*.*)

A default exception handler for unknown state-event combinations is 
provided and therefore a specification a your own exception handling is
optional.

After creating a new FSM, the initial state is set to the first defined 
state in your state transition table. With add(t) and delete(t), new state
transition can be added and removed later. 

A DEBUG-like method called silent is included to prevent wise-guy remarks
about things you shouldn't be doing. 

USAGE EXAMPLES:
------------------------------------------------------------------------------- 
FSM = require "fsm"

function action1() print("Performing action 1") end
function action2() print("Performing action 2") end

-- Define your state transitions here
local myStateTransitionTable = {
	{"state1", "event1", "state2", action1},
	{"state2", "event2", "state3", action2},
	{"*",      "event3", "state2", action1},  -- for any state
	{"*", 	   "*",	     "state2", action2}   -- exception handler
}

-- Create your finite state machine
fsm = FSM.new(myStateTransitionTable)

-- Use your finite state machine 
-- which starts by default with the first defined state
print("Current FSM state: " .. fsm:get())

-- Or you can set another state
fsm:set("state2")							
print("Current FSM state: " .. fsm:get())

-- Resond on "event" and last set "state"
fsm:fire("event2")
print("Current FSM state: " .. fsm:get())

Output:
-------
Current FSM state: state1
Current FSM state: state2
Performing action 2
Current FSM state: state3

REMARKS:
-------------------------------------------------------------------------------
Sub-states are not supported by additional methods to keep the code simple.
If you need sub-states, you can create them as 'state.substate' directly.

A specific remove method is not provided because I didn't need one (I think)
But feel free to implement one yourself :-)

One more thing, did I already mentioned that I am new to Lua?
Well, I learn a lot of other examples, so do not forget yours. 

CONCLUSION:
-------------------------------------------------------------------------------
A small amount of code is required to use the power of a Finite State Machine.

I wrote this code to implement generic graphical objects where the presentation 
and behaviour of the objects can be specified by using state-transition tables.
This resulted in less code (and less bugs), a higher modularity and above all a 
reduction of the complexity.

Finite state machines can be used to force (at least parts of) your code into 
deterministic behaviour. 

Have fun.

About

Finite State Machine library for Lua

License:Other