I was trying to explain for my programmers, what I exactly means with:
"Keep the navigation of yours FSM classes out of state classes, just sinalize that on the implementation"
I've decided to code a very simple sample to explain what I meaning.
#include "stdafx.h"
#include <windows.h>
#include <mmsystem.h>
#include <assert.h>
#include <conio.h>
#include "Alarm.h"
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#pragma comment( lib, "Winmm.lib" )
enum STATE_TRIGGERS { NONE = 0, BACK, NEXT };
class IState
{
public:
virtual void Enter() = 0;
virtual STATE_TRIGGERS Run() = 0;
virtual void Exit() = 0;
};
class StateMachine
{
private:
IState *_currentState;
vector<const IState *const> _initialStateList;
vector<const STATE_TRIGGERS> _triggersList;
vector<const IState *const> _finalStateList;
public:
void RegisterStateTrigger(const IState *const initalState, const STATE_TRIGGERS st, const IState *const finalState )
{
_initialStateList.push_back( initalState );
_triggersList.push_back( st );
_finalStateList.push_back( finalState );
return;
}
StateMachine( IState *const initialState ) : _currentState( initialState ){ _currentState->Enter(); };
~StateMachine() {};
void Loop()
{
STATE_TRIGGERS st = _currentState->Run();
if ( st == NONE ) return;
vector<const IState *const>::iterator index;
int j = 0;
for( index = _initialStateList.begin(); index != _initialStateList.end(); ++index, ++j )
if ((*index) == _currentState )
{
STATE_TRIGGERS st2 = _triggersList[j];
if (st == st2)
{
_currentState->Exit();
_currentState = const_cast<IState *>( _finalStateList[j] );
_currentState->Enter();
break;
}//if
}//if
}
};
class Preparation1 : public IState
{
private:
Alarm _a;
public:
void Enter(){ cout << "Preparation 1" << endl; _a.SetAlarm( 3000 ); };
STATE_TRIGGERS Run()
{
if (_a.ISTimeOut()) return BACK;
return NONE;
};
void Exit(){};
};
class Preparation2 : public IState
{
private:
Alarm _a;
public:
void Enter(){ cout << "Preparation 2" << endl; _a.SetAlarm( 3000 ); };
STATE_TRIGGERS Run()
{
if (_a.ISTimeOut()) return NEXT;
return NONE;
};
void Exit(){};
};
class Preparation3 : public IState
{
private:
Alarm _a;
public:
void Enter(){ cout << "Preparation 3" << endl; _a.SetAlarm( 3000 ); };
STATE_TRIGGERS Run()
{
if (_a.ISTimeOut()) return NEXT;
return NONE;
};
void Exit(){};
};
class Out : public IState
{
private:
Alarm _a;
public:
void Enter(){ cout << "I'm out!" << endl; _a.SetAlarm( 3000 ); };
STATE_TRIGGERS Run()
{
return NONE;
};
void Exit(){};
};
class Game : public IState
{
private:
Alarm _a;
public:
void Enter(){ cout << "In Game" << endl; _a.SetAlarm( 3000 ); };
STATE_TRIGGERS Run()
{
return NONE;
};
void Exit(){};
};
int _tmain(int argc, _TCHAR* argv[])
{
Preparation1 prep1;
Preparation2 prep2;
Preparation3 prep3;
Game game;
Out out;
IState *pState = &prep1;
StateMachine sm( &prep1 );
sm.RegisterStateTrigger( &prep1, NEXT, &prep2 );
sm.RegisterStateTrigger( &prep1, BACK, &out );
sm.RegisterStateTrigger( &prep2, NEXT, &prep3 );
sm.RegisterStateTrigger( &prep2, BACK, &out );
sm.RegisterStateTrigger( &prep3, NEXT, &game );
sm.RegisterStateTrigger( &prep3, BACK, &out );
while(1)
{
sm.Loop();
}
return 0;
}




