diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c27675..ac85afd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(AdversarialSearch/Minimax) add_subdirectory(Miscellaneous) add_subdirectory(NeuralNetwork/Perceptron) add_subdirectory(NeuralNetwork/MLP) +add_subdirectory(FSM) \ No newline at end of file diff --git a/FSM/CMakeLists.txt b/FSM/CMakeLists.txt new file mode 100644 index 0000000..7064648 --- /dev/null +++ b/FSM/CMakeLists.txt @@ -0,0 +1,5 @@ +set(FILES + FSM.cpp +) +add_compile_definitions(ENABLE_FSM_DEBUG) +add_executable(FSM ${FILES}) diff --git a/FSM/FSM.cpp b/FSM/FSM.cpp new file mode 100644 index 0000000..71e443d --- /dev/null +++ b/FSM/FSM.cpp @@ -0,0 +1,28 @@ +#include "StateMachine.h" +#include "MoveTo.h" +#include "Idle.h" + +using namespace std; + +int main() +{ + FSM::StateMachine fsm; + + fsm.TransitionTo(new FSM::Idle(), true); + fsm.TransitionTo(new FSM::MoveTo()); + fsm.Tick(); + fsm.TransitionTo(nullptr); + cout << endl; + + fsm.TransitionTo(nullptr); + fsm.TransitionTo(new FSM::Idle(), true); + fsm.TransitionTo(nullptr); + cout << endl; + + fsm.TransitionTo(nullptr); + fsm.TransitionTo(new FSM::MoveTo()); + fsm.Tick(); + fsm.TransitionTo(nullptr); + + return 0; +} diff --git a/FSM/Idle.h b/FSM/Idle.h new file mode 100644 index 0000000..c72a316 --- /dev/null +++ b/FSM/Idle.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "State.h" + +namespace FSM +{ + class Idle : public State + { + ~Idle() + { + // + } + + void OnEnter() + { + // + } + + void OnUpdate() + { + // + } + + void OnExit() + { + // + } + }; +} diff --git a/FSM/MoveTo.h b/FSM/MoveTo.h new file mode 100644 index 0000000..6515460 --- /dev/null +++ b/FSM/MoveTo.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "State.h" + +namespace FSM +{ + class MoveTo : public State + { + ~MoveTo() + { + // + } + + void OnEnter() + { + // + } + + void OnUpdate() + { + // + } + + void OnExit() + { + // + } + }; +} diff --git a/FSM/State.h b/FSM/State.h new file mode 100644 index 0000000..5ab32f8 --- /dev/null +++ b/FSM/State.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace FSM +{ + class State + { + public: + virtual ~State() = 0; + const char* name() const + { + return typeid(*this).name(); + } + virtual void OnEnter() = 0; + virtual void OnUpdate() = 0; + virtual void OnExit() = 0; + }; + + State::~State() + { + // + } +} diff --git a/FSM/StateMachine.h b/FSM/StateMachine.h new file mode 100644 index 0000000..6f27aae --- /dev/null +++ b/FSM/StateMachine.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include "State.h" + +namespace FSM +{ + class StateMachine + { + private: + State* _deferredNextState; + std::unique_ptr _currentState; + + void inline ApplyStateTransition() + { + if (!_deferredNextState) + { + return; + } + if (_currentState) + { +#ifdef ENABLE_FSM_DEBUG + std::cout << _currentState->name() << ": OnExit()" << std::endl; +#endif + _currentState->OnExit(); + } + _currentState.reset(_deferredNextState); +#ifdef ENABLE_FSM_DEBUG + std::cout << _currentState->name() << ": OnEnter()" << std::endl; +#endif + if (_currentState) + { + _currentState->OnEnter(); + } + _deferredNextState = nullptr; + } + + public: + ~StateMachine() + { + if (_deferredNextState) + { + delete _deferredNextState; + } + } + + void Tick() + { + ApplyStateTransition(); + if (_currentState) + { +#ifdef ENABLE_FSM_DEBUG + std::cout << _currentState->name() << ": OnUpdate()" << std::endl; +#endif + _currentState->OnUpdate(); + } + } + + void TransitionTo(State* const pNewState, bool immediate = false) + { + if (pNewState == _currentState.get()) + { +#ifdef ENABLE_FSM_DEBUG + std::cout << "Trying transitioning to same state! " << pNewState->name() << std::endl; +#endif + return; + } +#ifdef ENABLE_FSM_DEBUG + std::cout << "FSM - Transitioning to '" << (pNewState == nullptr ? "NULL" : pNewState->name()) << "' / immediate = " << std::boolalpha << immediate << std::endl; +#endif + _deferredNextState = pNewState; + if (immediate) + { + Tick(); + } + } + }; +}