state_lite.js v0.1.1
state_lite.js
This project is the smaller sibling to state.js, implementing the main capabilities of a finite state machine.
The current beta version is: 0.1.1.
If you like it, star it...
#Notes This implementation of finite state machines provides the common capabilities required; notable omissions are:
- no orthogonal regions
- no explicit final state (final states are states without any outward transitions
- no expplicit pseudo states
- the initial state of a composite state is the first child created
- history semantics are set on the composite state itself
- choice/junctions can be implemented as states with completion transitions
#Quick example# The example below implements this state machine.
Note that the circles in the top-right indocate the initial stating state of composite states and the H* indicates that the composite state operates with Deep History semantics.
In this example, a simple casette controller is modelled; the flipped state has been added to demonstrate deep history, whenever the state machine transitions from flipped to operational, the last known child state of operational (and all its sub-states) is restored. You can investigate history semantics further by editing the source in the examples.
Firstly, we create the state machine:
// create the top-level state machine (no parent defined)
var player = new State("player");
// create the rest of teh state machine hierarchy (parents defined)
var operational = new State("operational", player, History.Deep);
var flipped = new State("flipped", player);
var final = new State("final", player);
var stopped = new State("stopped", operational);
var active = new State("active", operational);
var running = new State("running", active);
var paused = new State("paused", active);
// create transitions between states with their guard conditions
transition(stopped, active, function (s) { return s === "play"; });
transition(active, stopped, function (s) { return s === "stop"; });
transition(running, paused, function (s) { return s === "pause"; });
transition(paused, running, function (s) { return s === "play"; });
transition(operational, flipped, function (s) { return s === "flip"; });
transition(flipped, operational, function (s) { return s === "flip"; });
transition(operational, final, function (s) { return s === "off"; });
// add some behaviour
active.entry = [engageHead];
active.exit = [disengageHead];
running.entry = [startMotor];
running.exit = [stopMotor];
Then it needs initialisation; this enters the initial starting state of the top-level composite state:
player.initialise();
If you look at the console output, you'll see the following:
Enter: player
Enter: player.operational
Enter: player.operational.stopped
To effect a state transition, essages are passed to the top-level state machine for processing:
player.process("play");
player.process("pause");
These messages are evaluated at the top-level for potential transitions then delegated to the current child state for processing.
In this example, the "play" and "pause" messages will effect transitions resulting in the following console output:
Leave: player.operational.stopped
Enter: player.operational.active
Enter: player.operational.active.running
Leave: player.operational.active.running
Enter: player.operational.active.paused
In addition, the entry and exit behavior of the active and running states will be called as appropriate.