diff --git a/builder.hpp b/builder.hpp index ce8b995..6b0e050 100644 --- a/builder.hpp +++ b/builder.hpp @@ -53,7 +53,7 @@ class Builder : DeadSimpleFSM { string read_line(FILE *build_out, bool &done_out); FILE *start_command(string &build_cmd); - void event(BuildEvent ev) override { + void event(BuildEvent ev) { try { if(ev == QUIT) { exit(ev); diff --git a/fsm.hpp b/fsm.hpp index 82dce66..d0fe917 100644 --- a/fsm.hpp +++ b/fsm.hpp @@ -3,9 +3,9 @@ #include #ifndef FSM_DEBUG -#define FSM_STATE(C, S, F, E) case C::S: F(E); break +#define FSM_STATE(C, S, F, E, ...) case C::S: F(E, ##__VA_ARGS__); break #else -#define FSM_STATE(C, S, F, E) case C::S: fmt::println(">> " #C " " #S ":" #F " event={}, state={}", int(E), int(_state)); F(E); fmt::println("<< " #C " state={}", int(_state)); break +#define FSM_STATE(C, S, F, E, ...) case C::S: fmt::println(">> " #C " " #S ":" #F " event={}, state={}", int(E), int(_state)); F(E, ##__VA_ARGS__); fmt::println("<< " #C " state={}", int(_state)); break #endif template @@ -15,7 +15,8 @@ protected: S _state = S::START; public: - virtual void event(E event) = 0; + template + void event(E event, Types... args); void state(S next_state) { _state = next_state; diff --git a/game_engine.hpp b/game_engine.hpp index 035980d..3b517f5 100644 --- a/game_engine.hpp +++ b/game_engine.hpp @@ -48,32 +48,15 @@ class GameEngine : DeadSimpleFSM { int determine_damage(string &type); bool is_dead(); - void event(GameEvent ev, string &hit_type) { - switch(_state) { - case GameState::IN_ROUND: - in_round(ev, hit_type); - break; - default: - event(ev); - } - } - - void event(GameEvent ev, const char *hit_type) { - string ht{hit_type}; - event(ev, ht); - } - - void event(GameEvent ev) { + void event(GameEvent ev, string hit_type="") { switch(_state) { FSM_STATE(GameState, START, start, ev); FSM_STATE(GameState, IDLE, idle, ev); FSM_STATE(GameState, DEAD, dead, ev); FSM_STATE(GameState, SUCCESS, success, ev); FSM_STATE(GameState, FAILURE, failure, ev); - case GameState::IN_ROUND: { - string hit_type = ""; + case GameState::IN_ROUND: in_round(ev, hit_type); - } break; } } diff --git a/meson.build b/meson.build index eba88b8..aa39278 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,7 @@ executable('escape_turings_tarpit', runtests = executable('runtests', [ 'game_engine.cpp', 'tests/game_engine.cpp', + 'tests/fsm.cpp', ], dependencies: dependencies + [catch2]) diff --git a/scratchpad/fsmtest.cpp b/scratchpad/fsmtest.cpp deleted file mode 100644 index 4864330..0000000 --- a/scratchpad/fsmtest.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "../fsm.hpp" - -using namespace fmt; - -enum class MyState { - START, RUNNING, END -}; - -enum class MyEvent { - STARTED, PUSH, QUIT -}; - -class MyFSM : DeadSimpleFSM { -public: - void event(MyEvent ev) override { - switch(_state) { - FSM_STATE(MyState, START, start, ev); - FSM_STATE(MyState, RUNNING, push, ev); - FSM_STATE(MyState, END, quit, ev); - } - } - - void start(MyEvent ev) { - println("<<< START"); - state(MyState::RUNNING); - } - - void push(MyEvent ev) { - println("<<< RUN"); - state(MyState::RUNNING); - } - - void quit(MyEvent ev) { - println("<<< STOP"); - state(MyState::END); - } -}; - -int main() { - MyFSM fsm; - - fsm.event(MyEvent::STARTED); - fsm.event(MyEvent::PUSH); - fsm.event(MyEvent::PUSH); - fsm.event(MyEvent::PUSH); - fsm.event(MyEvent::QUIT); -} diff --git a/scratchpad/meson.build b/scratchpad/meson.build index 0597ebf..cef6686 100644 --- a/scratchpad/meson.build +++ b/scratchpad/meson.build @@ -10,9 +10,6 @@ executable('jsontest', 'jsontest.cpp', executable('threadtest', 'threadtest.cpp', dependencies: dependencies) -executable('fsmtest', 'fsmtest.cpp', - dependencies: dependencies) - executable('badref', 'badref.cpp', dependencies: dependencies) diff --git a/tests/fsm.cpp b/tests/fsm.cpp new file mode 100644 index 0000000..0440098 --- /dev/null +++ b/tests/fsm.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include "../fsm.hpp" + +using namespace fmt; +using std::string; + +enum class MyState { + START, RUNNING, END +}; + +enum class MyEvent { + STARTED, PUSH, QUIT +}; + +class MyFSM : public DeadSimpleFSM { +public: + void event(MyEvent ev, string data="") { + switch(_state) { + FSM_STATE(MyState, START, START, ev); + FSM_STATE(MyState, RUNNING, RUNNING, ev, data); + FSM_STATE(MyState, END, END, ev); + } + } + + void START(MyEvent ev) { + println("<<< START"); + state(MyState::RUNNING); + } + + void RUNNING(MyEvent ev, string &data) { + if(ev == MyEvent::QUIT) { + println("<<< QUITTING {}", data); + state(MyState::END); + } else { + println("<<< RUN: {}", data); + state(MyState::RUNNING); + } + } + + void END(MyEvent ev) { + println("<<< STOP"); + state(MyState::END); + } +}; + +TEST_CASE("confirm fsm works with optional data", "[utils]") { + MyFSM fsm; + + REQUIRE(fsm.in_state(MyState::START)); + + fsm.event(MyEvent::STARTED); + REQUIRE(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + REQUIRE(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + REQUIRE(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + REQUIRE(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::QUIT, "DONE!"); + REQUIRE(fsm.in_state(MyState::END)); +}