Skip to content

Instantly share code, notes, and snippets.

@rpoisel
Last active April 17, 2023 08:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rpoisel/6de075a672e2f9152a9e15274be5f661 to your computer and use it in GitHub Desktop.
Save rpoisel/6de075a672e2f9152a9e15274be5f661 to your computer and use it in GitHub Desktop.
Simple State-Machine similar to HFSM2
#include <csignal>
#include <cstdlib>
#include <ctime>
#include <atomic>
#include <chrono>
#include <iostream>
#include <optional>
#include <thread>
#include <variant>
using namespace std::chrono_literals;
static inline std::size_t rand_number(std::size_t min, std::size_t max) {
return min + std::rand() / ((RAND_MAX + 1u) / max);
}
template <class... States> class FSM {
public:
using StateVariant = std::variant<States...>;
using OptionalStateVariant = std::optional<StateVariant>;
FSM(StateVariant initialState) : curState{std::move(initialState)} {}
void update() {
auto newState = std::visit(
[](auto &arg) -> OptionalStateVariant {
arg.update();
return transition(arg);
},
curState);
if (newState) {
curState = std::move(newState.value());
}
std::this_thread::sleep_for(500ms);
}
private:
StateVariant curState;
};
class LightOn;
class LightOff;
using StateVariant = std::variant<LightOn, LightOff>;
using OptionalStateVariant = std::optional<StateVariant>;
class LightOn {
public:
LightOn(std::size_t c) : cycles{c}, cycle{0} {}
virtual ~LightOn() = default;
void update() {
std::cout << "Light on: " << ++cycle << " of " << cycles << std::endl;
}
friend OptionalStateVariant transition(LightOn &on);
private:
std::size_t cycles;
std::size_t cycle;
};
class LightOff {
public:
LightOff() = default;
virtual ~LightOff() = default;
void update() { std::cout << "Light off" << std::endl; }
friend OptionalStateVariant transition(LightOff &on);
};
OptionalStateVariant transition(LightOn &on) {
if (on.cycle == on.cycles) {
return LightOff();
}
return std::nullopt;
}
OptionalStateVariant transition(LightOff &off) {
return LightOn(rand_number(1, 6));
}
static std::atomic_bool is_running = true;
auto main() noexcept -> int {
std::srand(std::time(nullptr));
FSM<LightOn, LightOff> fsm{LightOff{}};
std::signal(SIGINT, [](int signal) -> void { is_running = false; });
while (is_running) {
fsm.update();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment