Refined the FSM to allow easily passing in data to the even handler and state functions.
This commit is contained in:
parent
40ba7f0b66
commit
c9425aebf9
7 changed files with 75 additions and 74 deletions
|
@ -53,7 +53,7 @@ class Builder : DeadSimpleFSM<BuildState, BuildEvent> {
|
||||||
string read_line(FILE *build_out, bool &done_out);
|
string read_line(FILE *build_out, bool &done_out);
|
||||||
FILE *start_command(string &build_cmd);
|
FILE *start_command(string &build_cmd);
|
||||||
|
|
||||||
void event(BuildEvent ev) override {
|
void event(BuildEvent ev) {
|
||||||
try {
|
try {
|
||||||
if(ev == QUIT) {
|
if(ev == QUIT) {
|
||||||
exit(ev);
|
exit(ev);
|
||||||
|
|
7
fsm.hpp
7
fsm.hpp
|
@ -3,9 +3,9 @@
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#ifndef FSM_DEBUG
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
template<typename S, typename E>
|
template<typename S, typename E>
|
||||||
|
@ -15,7 +15,8 @@ protected:
|
||||||
S _state = S::START;
|
S _state = S::START;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void event(E event) = 0;
|
template<typename... Types>
|
||||||
|
void event(E event, Types... args);
|
||||||
|
|
||||||
void state(S next_state) {
|
void state(S next_state) {
|
||||||
_state = next_state;
|
_state = next_state;
|
||||||
|
|
|
@ -48,32 +48,15 @@ class GameEngine : DeadSimpleFSM<GameState, GameEvent> {
|
||||||
int determine_damage(string &type);
|
int determine_damage(string &type);
|
||||||
bool is_dead();
|
bool is_dead();
|
||||||
|
|
||||||
void event(GameEvent ev, string &hit_type) {
|
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) {
|
|
||||||
switch(_state) {
|
switch(_state) {
|
||||||
FSM_STATE(GameState, START, start, ev);
|
FSM_STATE(GameState, START, start, ev);
|
||||||
FSM_STATE(GameState, IDLE, idle, ev);
|
FSM_STATE(GameState, IDLE, idle, ev);
|
||||||
FSM_STATE(GameState, DEAD, dead, ev);
|
FSM_STATE(GameState, DEAD, dead, ev);
|
||||||
FSM_STATE(GameState, SUCCESS, success, ev);
|
FSM_STATE(GameState, SUCCESS, success, ev);
|
||||||
FSM_STATE(GameState, FAILURE, failure, ev);
|
FSM_STATE(GameState, FAILURE, failure, ev);
|
||||||
case GameState::IN_ROUND: {
|
case GameState::IN_ROUND:
|
||||||
string hit_type = "";
|
|
||||||
in_round(ev, hit_type);
|
in_round(ev, hit_type);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ executable('escape_turings_tarpit',
|
||||||
runtests = executable('runtests', [
|
runtests = executable('runtests', [
|
||||||
'game_engine.cpp',
|
'game_engine.cpp',
|
||||||
'tests/game_engine.cpp',
|
'tests/game_engine.cpp',
|
||||||
|
'tests/fsm.cpp',
|
||||||
],
|
],
|
||||||
dependencies: dependencies + [catch2])
|
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',
|
executable('threadtest', 'threadtest.cpp',
|
||||||
dependencies: dependencies)
|
dependencies: dependencies)
|
||||||
|
|
||||||
executable('fsmtest', 'fsmtest.cpp',
|
|
||||||
dependencies: dependencies)
|
|
||||||
|
|
||||||
executable('badref', 'badref.cpp',
|
executable('badref', 'badref.cpp',
|
||||||
dependencies: dependencies)
|
dependencies: dependencies)
|
||||||
|
|
||||||
|
|
67
tests/fsm.cpp
Normal file
67
tests/fsm.cpp
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue