C++ state machine

[ permalink ] [ download ]
/*
 *
 * Maquina de estados , utilizando el patron state y templates
 * Author : Jon Ander Ortiz
 * License: GPLV3 : ^_^
 *
 */

#include <iostream>
using namespace std; 


/*Clase State con acceso a la clase de la que forma el estado*/

template <class C> class State{
protected:
	C* owner;
public:
	State(C* o_):owner(o_){};
	virtual ~State (){}
	virtual void enter (){}
	virtual void execute (){}
	virtual void exit (){}
};

/* Clase que implementa los métodos de gestión de estados */

template <class T> class StateMachine { 
	private:
		State<T> * current;
		State<T> * last;
		State<T> * context; 			//Este viene siendo un tanto opcional
	
	public:
		void setCurrentState(State<T>*);
	    State<T>* getCurrentState();
       	void update(); //Updatea la FSM (Finite state machine) 
		void changeState (State<T>* );
		void returnLastState ();
};
template <class T> void StateMachine<T>::setCurrentState(State<T> * current_)
{this->current = current_;}
template <class T> State<T>* StateMachine<T>::getCurrentState()
{return this->current;}
template <class T> void StateMachine<T>::update()
{this->current->execute();}
template <class T> void StateMachine<T>::changeState(State<T>* t)
{
	this->current->exit();
	delete this->last;
	this->last = this->current;
	this->current = t;
	this->current->enter();
}
template <class T> void StateMachine<T>::returnLastState()
{
		this->current->exit();
		this->last->enter();
}



//Diagrama de estados para el tema este:
//     Estados de animo del objeto controlado (Cuando va hablando va cambiando de estado) :
//              Estado 1                     Estado 2                  Estado 3
//             Tiene pena ---------------->Esta Contento------------->Tiene Miedo
//                     /|\                                            |
//                      |_____________________________________________|
//

/*
Hay que definir primero las clases y luego los métodos todos seguidos, de esta manera podemos acceder de uno a otro sin problema, si lo ponemos de otra manera ya empieza a dar por saco
*/

class Controlado //Controlado tiene una bonita maquina de estados que regula su funcionamiento
{
private:
	StateMachine<Controlado> sm;
public:
	Controlado ();
	StateMachine<Controlado> * getStateMachine();
	void hablar();	
};


/*Definición de los estados posibles, heredan de la plantilla state instanciada con el elemento 
controlado, es decir, que son un estado del elemento controlado */

class ControladoConcreteStatePena : public State<Controlado>
{
private:
	//Aqui rollos internos variados de X o de Y
public:
	ControladoConcreteStatePena(Controlado * ctld);
	void enter ();
	void execute ();
	void exit ();
};

class ControladoConcreteStateFeliz : public State<Controlado>
{
private:
	//Aqui rollos internos variados de X o de Y
public:
	ControladoConcreteStateFeliz(Controlado * ctld);
	void enter ();
	void execute ();
	void exit ();
};

class ControladoConcreteStateMiedo: public State<Controlado>
{
private:
public:
	ControladoConcreteStateMiedo(Controlado * ctld);
	void enter ();
	void execute ();
	void exit ();
};

Controlado::Controlado()
{
	sm.setCurrentState(new ControladoConcreteStatePena(this));
}
StateMachine<Controlado>* Controlado::getStateMachine()
{return &(this->sm);}
void Controlado::hablar()
{
	sm.update(); //Ahora llama a el metodo execute de su estado actual
				 //En este punto hay dos maneras de funcionar que el mísmo execute 
				 //cambie el estado de su Controlado, o que se controle desde la StateMachine 
				 //Yo lo he echo desde el hijo, de echo es una de las razones de la
				// arquitectura de la plantilla
}
ControladoConcreteStatePena::ControladoConcreteStatePena(Controlado * ctld): State<Controlado>(ctld)
{/*For other purpouses :P*/}
void ControladoConcreteStatePena::enter()
{
 //Aqui tenemos acceso a lo que viene siendo el elemento controlado
	cout<<"Entramos en el estado de pena"<<endl;
}

void ControladoConcreteStatePena::execute()
{
	cout<<"Ejecutamos en el estado pena"<<endl;
	cout<<"Ahi que penita que tengo!!!!"<<endl;
	this->owner->getStateMachine()->changeState(new ControladoConcreteStateFeliz(this->owner));
}

void ControladoConcreteStatePena::exit()
{
	cout<<"Ejecutamos salir del estado de pena"<<endl;
	cout<<"Nos vamos animando"<<endl;
}

ControladoConcreteStateFeliz::ControladoConcreteStateFeliz(Controlado * ctld): State<Controlado>(ctld) 
{}
void ControladoConcreteStateFeliz::enter()
{
	cout<<"Entramos en el estado de felicidad"<<endl;
}
void ControladoConcreteStateFeliz::execute()
{
	cout<<"Ahi que contento que estoy!!!!!"<<endl;
	this->owner->getStateMachine()->changeState(new ControladoConcreteStateMiedo(this->owner));

}
void ControladoConcreteStateFeliz::exit()
{
	cout<<"Ejecutamos salir del estado de felicidad"<<endl;
	cout<<"Y nos vamos asustando"<<endl;
}

ControladoConcreteStateMiedo::ControladoConcreteStateMiedo(Controlado * ctld): State<Controlado>(ctld) 
{}

void ControladoConcreteStateMiedo::enter()
{
	cout<<"Entramos en el estado del miedo"<<endl;
}
void ControladoConcreteStateMiedo::execute()
{
	cout<<"Me cago del miedo!!!!!"<<endl;
		this->owner->getStateMachine()->changeState(new ControladoConcreteStatePena(this->owner));

}
void ControladoConcreteStateMiedo::exit()
{
	cout<<"Ejecutamos salir del estado de Miedo"<<endl;
	cout<<"Y nos va entrando la penita"<<endl;
}

int main (int argc, char * argv [])
{
	Controlado * a = new Controlado();
	a->hablar();
	a->hablar();
	a->hablar();
	return 0;
}
hits counter