From e4cc115baab45a7ab833bd5f76ffeea457e69dfd Mon Sep 17 00:00:00 2001 From: andreimesquita Date: Wed, 19 Aug 2020 15:05:44 -0300 Subject: [PATCH 1/2] Implementing FSM with immediate and deffered transitions between states --- CMakeLists.txt | 1 + FSM/CMakeLists.txt | 5 +++ FSM/FSM.cpp | 21 ++++++++++++ FSM/Idle.h | 30 +++++++++++++++++ FSM/MoveTo.h | 30 +++++++++++++++++ FSM/State.h | 24 ++++++++++++++ FSM/StateMachine.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 193 insertions(+) create mode 100644 FSM/CMakeLists.txt create mode 100644 FSM/FSM.cpp create mode 100644 FSM/Idle.h create mode 100644 FSM/MoveTo.h create mode 100644 FSM/State.h create mode 100644 FSM/StateMachine.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d8a7ee..bd909a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(AdversarialSearch/Minimax) add_subdirectory(NeuralNetwork/Common) 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..42574db --- /dev/null +++ b/FSM/FSM.cpp @@ -0,0 +1,21 @@ +#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); + fsm.TransitionTo(new FSM::Idle(), true); + + fsm.TransitionTo(nullptr); + fsm.TransitionTo(new FSM::MoveTo()); + fsm.Tick(); + 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..ac9cb9f --- /dev/null +++ b/FSM/StateMachine.h @@ -0,0 +1,82 @@ +#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 + _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 == nullptr) + { + _currentState = nullptr; + return; + } + 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->name() << "' / immediate = " << std::boolalpha << immediate << std::endl; +#endif + _deferredNextState = pNewState; + if (immediate) + { + Tick(); + } + } + }; +} From 662f8d3d3979e4519797bb5f72a9af8af64c50f0 Mon Sep 17 00:00:00 2001 From: andreimesquita Date: Sat, 29 Aug 2020 13:34:41 -0300 Subject: [PATCH 2/2] Fixing some validations and logs --- FSM/FSM.cpp | 7 +++++++ FSM/StateMachine.h | 12 +++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/FSM/FSM.cpp b/FSM/FSM.cpp index 42574db..71e443d 100644 --- a/FSM/FSM.cpp +++ b/FSM/FSM.cpp @@ -7,15 +7,22 @@ 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/StateMachine.h b/FSM/StateMachine.h index ac9cb9f..6f27aae 100644 --- a/FSM/StateMachine.h +++ b/FSM/StateMachine.h @@ -30,7 +30,10 @@ namespace FSM #ifdef ENABLE_FSM_DEBUG std::cout << _currentState->name() << ": OnEnter()" << std::endl; #endif - _currentState->OnEnter(); + if (_currentState) + { + _currentState->OnEnter(); + } _deferredNextState = nullptr; } @@ -57,11 +60,6 @@ namespace FSM void TransitionTo(State* const pNewState, bool immediate = false) { - if (pNewState == nullptr) - { - _currentState = nullptr; - return; - } if (pNewState == _currentState.get()) { #ifdef ENABLE_FSM_DEBUG @@ -70,7 +68,7 @@ namespace FSM return; } #ifdef ENABLE_FSM_DEBUG - std::cout << "FSM - Transitioning to '" << pNewState->name() << "' / immediate = " << std::boolalpha << immediate << std::endl; + std::cout << "FSM - Transitioning to '" << (pNewState == nullptr ? "NULL" : pNewState->name()) << "' / immediate = " << std::boolalpha << immediate << std::endl; #endif _deferredNextState = pNewState; if (immediate)