Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- namespace Development {
- public class StateMachine<TState, TEvent>
- where TState : IComparable
- where TEvent : IComparable {
- #region Instance Fields
- private State currentState;
- private Dictionary<TState, State> states;
- private Queue<Builder> builders;
- #endregion
- #region Constructors
- public StateMachine() {
- states = new Dictionary<TState, State>();
- builders = new Queue<Builder>();
- }
- #endregion
- #region Instance Methods
- public IBuilder Configure(TState stateID) {
- Builder builder = new Builder(stateID, this);
- builders.Enqueue(builder);
- return builder;
- }
- public bool Initialize(TState originID) {
- while (builders.Count > 0) {
- builders.Dequeue().Finish();
- }
- if (states.TryGetValue(originID, out State state)) {
- currentState = state;
- currentState.OnEnter();
- return true;
- }
- return false;
- }
- public void Fire(TEvent eventID) => currentState?.Fire(eventID);
- private State GetOrCreateState(TState stateID) {
- State state;
- if (!states.TryGetValue(stateID, out state)) {
- state = states[stateID] = new State(stateID, this);
- }
- return state;
- }
- #endregion
- #region Classes
- private class State : StateableItem {
- #region Properties
- public TState StateID { get; }
- public StateMachine<TState, TEvent> Machine { get; }
- public Action EnterAction {
- private get => enterAction;
- set {
- if (item == null) {
- enterAction = value;
- } else if (value != null) {
- throw new Exception("StateableItem already set.");
- }
- }
- }
- public Action LeaveAction {
- private get => leaveAction;
- set {
- if (item == null) {
- leaveAction = value;
- } else if (value != null) {
- throw new Exception("StateableItem already set.");
- }
- }
- }
- public StateableItem Item {
- private get => item;
- set {
- item = value;
- if (item != null) {
- enterAction = item.OnEnter;
- leaveAction = item.OnLeave;
- } else {
- enterAction = null;
- leaveAction = null;
- }
- }
- }
- #endregion
- #region Instance Fields
- protected internal Dictionary<TEvent, Transition> transitions;
- private Action enterAction;
- private Action leaveAction;
- private StateableItem item;
- #endregion
- #region Constructors
- public State(TState stateID, StateMachine<TState, TEvent> machine) {
- StateID = stateID;
- Machine = machine;
- transitions = new Dictionary<TEvent, Transition>();
- }
- #endregion
- #region Instance Methods
- protected internal void Fire(TEvent eventID) {
- if (transitions.TryGetValue(eventID, out Transition transition)) {
- transition.Fire();
- }
- }
- public override void OnEnter() => EnterAction?.Invoke();
- public override void OnLeave() => LeaveAction?.Invoke();
- #endregion
- }
- private class Transition {
- #region Properties
- public TEvent EventID { get; }
- public StateMachine<TState, TEvent> Machine { get; }
- public State Source { get; protected internal set; }
- public State Target { get; protected internal set; }
- #endregion
- #region Constructors
- public Transition(TEvent eventID, StateMachine<TState, TEvent> machine) {
- EventID = eventID;
- Machine = machine;
- }
- #endregion
- #region Instance Methods
- protected internal void Fire() {
- Source.OnLeave();
- Target.OnEnter();
- Machine.currentState = Target;
- }
- #endregion
- }
- private class Builder : IBuilder {
- #region Instance Fields
- private StateMachine<TState, TEvent> machine;
- private StateInfo sourceInfo;
- private List<TransitionInfo> transitions;
- private bool built;
- #endregion
- #region Constructors
- public Builder(TState stateID, StateMachine<TState, TEvent> machine) {
- this.machine = machine;
- sourceInfo.stateID = stateID;
- transitions = new List<TransitionInfo>();
- built = false;
- }
- #endregion
- #region Instance Methods
- public IBuilder Permit(TEvent onEventID, TState toStateID) {
- transitions.Add(new TransitionInfo {
- onEventID = onEventID,
- toStateID = toStateID
- });
- return this;
- }
- public IBuilder DefineState(StateableItem item) {
- sourceInfo.item = item;
- return this;
- }
- public IBuilder ExecuteOnEnter(Action action) {
- sourceInfo.enterAction = action;
- return this;
- }
- public IBuilder ExecuteOnLeave(Action action) {
- sourceInfo.leaveAction = action;
- return this;
- }
- protected internal void Finish() {
- if (!built) {
- State source = machine.GetOrCreateState(sourceInfo.stateID);
- source.EnterAction = sourceInfo.enterAction;
- source.LeaveAction = sourceInfo.leaveAction;
- if (sourceInfo.item != null) {
- source.Item = sourceInfo.item;
- }
- foreach (TransitionInfo info in transitions) {
- Transition transition = new Transition(info.onEventID, machine) {
- Source = source,
- Target = machine.GetOrCreateState(info.toStateID)
- };
- source.transitions[info.onEventID] = transition;
- }
- built = true;
- }
- }
- #endregion
- #region Classes
- private struct StateInfo {
- public TState stateID;
- public StateableItem item;
- public Action enterAction;
- public Action leaveAction;
- }
- private struct TransitionInfo {
- public TEvent onEventID;
- public TState toStateID;
- }
- #endregion
- }
- #endregion
- #region Interfaces
- public interface IBuilder {
- IBuilder Permit(TEvent onEventID, TState toStateID);
- IBuilder DefineState(StateableItem item);
- IBuilder ExecuteOnEnter(Action action);
- IBuilder ExecuteOnLeave(Action action);
- }
- #endregion
- }
- public abstract class StateableItem {
- #region Instance Methods
- public virtual void OnEnter() { }
- public virtual void OnLeave() { }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement