Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider providing some example code #3

Open
bivens-dev opened this issue May 28, 2023 · 4 comments
Open

Consider providing some example code #3

bivens-dev opened this issue May 28, 2023 · 4 comments
Assignees

Comments

@bivens-dev
Copy link

This library looks really interesting but it isn't immediately clear how to use it correctly. Perhaps by adding a couple of simple examples that highlight some of the usage patterns it could help make it more approachable.

I was thinking something along the lines of the following (but obviously using the correct API)

enum TrafficLightState {
  green,
  yellow,
  red,
}

enum TrafficLightEvent {
  timerExpired,
}

class TrafficLightStateMachine {
  final Machine<TrafficLightState, TrafficLightEvent> _stateMachine;

  TrafficLightStateMachine()
      : _stateMachine = Machine<TrafficLightState, TrafficLightEvent>(
          initialState: TrafficLightState.green,
          states: {
            TrafficLightState.green: State(
              onEnter: () => print('Green light'),
              transitions: {
                TrafficLightEvent.timerExpired: TrafficLightState.yellow,
              },
            ),
            TrafficLightState.yellow: State(
              onEnter: () => print('Yellow light'),
              transitions: {
                TrafficLightEvent.timerExpired: TrafficLightState.red,
              },
            ),
            TrafficLightState.red: State(
              onEnter: () => print('Red light'),
              transitions: {
                TrafficLightEvent.timerExpired: TrafficLightState.green,
              },
            ),
          },
        );

  void start() {
    while (true) {
      _stateMachine.transition(TrafficLightEvent.timerExpired);
      sleep(Duration(seconds: 1));
    }
  }
}

void main() {
  final trafficLight = TrafficLightStateMachine();
  trafficLight.start();
}
@jtmcdole
Copy link
Member

jtmcdole commented Jun 8, 2023

Ah, I thought I had the keyboard state machine in the tests section of code. That's not a bad example (though we'd have to restart the timer on every enter) and could be expanded with say a pedestrian wanting to cross.

@jtmcdole jtmcdole self-assigned this Jun 8, 2023
@macasas
Copy link

macasas commented May 21, 2024

Hi, I am also trying to implement a hierarchical state machine and I thought this repo looked promising. It would be nice to declare as per the example above, but that doesn't seem to be possible. There are no docs or examples, its 2 years old so would you suggest I look elsewhere, or is this still a viable option?

So here is my effort so far, but i cannot see a way to add a state to a machine, or machines to a state?
The only state in the machine is the root.
How do I add the states to the machine?
How do I make nested machines?

import 'package:hierarchical_state_machine/hierarchical_state_machine.dart';

enum TrafficLightState {
  red,
  amber,
  green,
}

enum TrafficLightEvent {
  stop,
  readyToGo,
  readyToStop,
  go
}
enum TrafficLightTransition {
  red2amber,
  amber2green,
  green2amber,
  amber2red
}

  void init() {
    //states
    var red = State(TrafficLightState.red);
    var amber = State(TrafficLightState.amber);
    var green = State(TrafficLightState.green);

    //events
    var stop = EventHandler(
      target: red,
      guard: null,
      action: (event, data) {
        print('stop action, light is red');
      },
      isLocalTransition: true
    );
    var readyToGo = EventHandler(
      target: amber,
      guard: null,
      action: (event, data) {
        print('readyTogo action, light is amber');
      },
      isLocalTransition: true
    );
    var readyToStop = EventHandler(
      target: amber,
      guard: null,
      action: (event, data) {
        print('readyToStop action, light is amber');
      },
      isLocalTransition: true
    );
    var go = EventHandler(
      target: green,
      guard: null,
      action: (event, data) {
        print('go action, light is green');
      },
      isLocalTransition: true
    );

    red.addHandler(readyToGo);
    amber.addHandler(stop);
    amber.addHandler(go);
    green.addHandler(readyToStop);

    //machine
    TrafficLightState root = TrafficLightState.red;

    final Machine<TrafficLightState, TrafficLightEvent> trafficlight = 
      Machine<TrafficLightState, TrafficLightEvent>(
        name: 'traffic_light',
        rootId: root,
      );
    

    //transitions

    // runs twice
    var loop = 2;
    while (loop > 0) {
      trafficlight.start();
      trafficlight.handle(TrafficLightEvent.stop);
      trafficlight.handle(TrafficLightEvent.readyToGo);
      trafficlight.handle(TrafficLightEvent.go);
      trafficlight.handle(TrafficLightEvent.readyToStop);
      trafficlight.handle(TrafficLightEvent.stop);
      loop--;
    }
  }

void main() {
  init();
}

@jtmcdole
Copy link
Member

@macasas maybe this can help for now (documentation can always be improved):

 final root = hsm.root;

final red = root.newChild(TrafficLightState.red);
final yellow = root.newChild(TrafficLightState.yellow); 
final green = root.newChild(TrafficLightState.green); 

as a bonus; its easier to add event handlers without allocating:

red.addHandler(
  target: amber,
  action: (event, data) {
    print('readyTogo action, light is amber');
  },
);

I use this library for personal projects, so it's not dead, it's just "stable".

@macasas
Copy link

macasas commented May 26, 2024

Thanks, I'm having a play :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants