Refined the FSM to allow easily passing in data to the even handler and state functions.

master
Zed A. Shaw 3 months ago
parent 40ba7f0b66
commit c9425aebf9
  1. 2
      builder.hpp
  2. 7
      fsm.hpp
  3. 21
      game_engine.hpp
  4. 1
      meson.build
  5. 48
      scratchpad/fsmtest.cpp
  6. 3
      scratchpad/meson.build
  7. 67
      tests/fsm.cpp

@ -53,7 +53,7 @@ class Builder : DeadSimpleFSM<BuildState, BuildEvent> {
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);

@ -3,9 +3,9 @@
#include <fmt/core.h>
#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<typename S, typename E>
@ -15,7 +15,8 @@ protected:
S _state = S::START;
public:
virtual void event(E event) = 0;
template<typename... Types>
void event(E event, Types... args);
void state(S next_state) {
_state = next_state;

@ -48,32 +48,15 @@ class GameEngine : DeadSimpleFSM<GameState, GameEvent> {
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;
}
}

@ -39,6 +39,7 @@ executable('escape_turings_tarpit',
runtests = executable('runtests', [
'game_engine.cpp',
'tests/game_engine.cpp',
'tests/fsm.cpp',
],
dependencies: dependencies + [catch2])

@ -1,48 +0,0 @@
#include <fmt/core.h>
#include "../fsm.hpp"
using namespace fmt;
enum class MyState {
START, RUNNING, END
};
enum class MyEvent {
STARTED, PUSH, QUIT
};
class MyFSM : DeadSimpleFSM<MyState, MyEvent> {
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);
}

@ -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)

@ -0,0 +1,67 @@
#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#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<MyState, MyEvent> {
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));
}
Loading…
Cancel
Save