Advertisement
Guest User

Untitled

a guest
Apr 22nd, 2019
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.98 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3.  
  4. namespace Development {
  5.  
  6.     public class StateMachine<TState, TEvent>
  7.         where TState : IComparable
  8.         where TEvent : IComparable {
  9.  
  10.         #region Instance Fields
  11.         private State currentState;
  12.         private Dictionary<TState, State> states;
  13.         private Queue<Builder> builders;
  14.         #endregion
  15.  
  16.         #region Constructors
  17.         public StateMachine() {
  18.             states = new Dictionary<TState, State>();
  19.             builders = new Queue<Builder>();
  20.         }
  21.         #endregion
  22.  
  23.         #region Instance Methods
  24.         public IBuilder Configure(TState stateID) {
  25.             Builder builder = new Builder(stateID, this);
  26.             builders.Enqueue(builder);
  27.             return builder;
  28.         }
  29.  
  30.         public bool Initialize(TState originID) {
  31.             while (builders.Count > 0) {
  32.                 builders.Dequeue().Finish();
  33.             }
  34.             if (states.TryGetValue(originID, out State state)) {
  35.                 currentState = state;
  36.                 currentState.OnEnter();
  37.                 return true;
  38.             }
  39.             return false;
  40.         }
  41.  
  42.         public void Fire(TEvent eventID) => currentState?.Fire(eventID);
  43.  
  44.         private State GetOrCreateState(TState stateID) {
  45.             State state;
  46.             if (!states.TryGetValue(stateID, out state)) {
  47.                 state = states[stateID] = new State(stateID, this);
  48.             }
  49.             return state;
  50.         }
  51.         #endregion
  52.  
  53.         #region Classes
  54.         private class State : StateableItem {
  55.  
  56.             #region Properties
  57.             public TState StateID { get; }
  58.             public StateMachine<TState, TEvent> Machine { get; }
  59.             public Action EnterAction {
  60.                 private get => enterAction;
  61.                 set {
  62.                     if (item == null) {
  63.                         enterAction = value;
  64.                     } else if (value != null) {
  65.                         throw new Exception("StateableItem already set.");
  66.                     }
  67.                 }
  68.             }
  69.             public Action LeaveAction {
  70.                 private get => leaveAction;
  71.                 set {
  72.                     if (item == null) {
  73.                         leaveAction = value;
  74.                     } else if (value != null) {
  75.                         throw new Exception("StateableItem already set.");
  76.                     }
  77.                 }
  78.             }
  79.             public StateableItem Item {
  80.                 private get => item;
  81.                 set {
  82.                     item = value;
  83.                     if (item != null) {
  84.                         enterAction = item.OnEnter;
  85.                         leaveAction = item.OnLeave;
  86.                     } else {
  87.                         enterAction = null;
  88.                         leaveAction = null;
  89.                     }
  90.                 }
  91.             }
  92.             #endregion
  93.  
  94.             #region Instance Fields
  95.             protected internal Dictionary<TEvent, Transition> transitions;
  96.             private Action enterAction;
  97.             private Action leaveAction;
  98.             private StateableItem item;
  99.             #endregion
  100.  
  101.             #region Constructors
  102.             public State(TState stateID, StateMachine<TState, TEvent> machine) {
  103.                 StateID = stateID;
  104.                 Machine = machine;
  105.                 transitions = new Dictionary<TEvent, Transition>();
  106.             }
  107.             #endregion
  108.  
  109.             #region Instance Methods
  110.             protected internal void Fire(TEvent eventID) {
  111.                 if (transitions.TryGetValue(eventID, out Transition transition)) {
  112.                     transition.Fire();
  113.                 }
  114.             }
  115.             public override void OnEnter() => EnterAction?.Invoke();
  116.             public override void OnLeave() => LeaveAction?.Invoke();
  117.             #endregion
  118.         }
  119.  
  120.         private class Transition {
  121.  
  122.             #region Properties
  123.             public TEvent EventID { get; }
  124.             public StateMachine<TState, TEvent> Machine { get; }
  125.             public State Source { get; protected internal set; }
  126.             public State Target { get; protected internal set; }
  127.             #endregion
  128.  
  129.             #region Constructors
  130.             public Transition(TEvent eventID, StateMachine<TState, TEvent> machine) {
  131.                 EventID = eventID;
  132.                 Machine = machine;
  133.             }
  134.             #endregion
  135.  
  136.             #region Instance Methods
  137.             protected internal void Fire() {
  138.                 Source.OnLeave();
  139.                 Target.OnEnter();
  140.                 Machine.currentState = Target;
  141.             }
  142.             #endregion
  143.         }
  144.  
  145.         private class Builder : IBuilder {
  146.  
  147.             #region Instance Fields
  148.             private StateMachine<TState, TEvent> machine;
  149.             private StateInfo sourceInfo;
  150.             private List<TransitionInfo> transitions;
  151.             private bool built;
  152.             #endregion
  153.  
  154.             #region Constructors
  155.             public Builder(TState stateID, StateMachine<TState, TEvent> machine) {
  156.                 this.machine = machine;
  157.                 sourceInfo.stateID = stateID;
  158.                 transitions = new List<TransitionInfo>();
  159.                 built = false;
  160.             }
  161.             #endregion
  162.  
  163.             #region Instance Methods
  164.             public IBuilder Permit(TEvent onEventID, TState toStateID) {
  165.                 transitions.Add(new TransitionInfo {
  166.                     onEventID = onEventID,
  167.                     toStateID = toStateID
  168.                 });
  169.                 return this;
  170.             }
  171.  
  172.             public IBuilder DefineState(StateableItem item) {
  173.                 sourceInfo.item = item;
  174.                 return this;
  175.             }
  176.  
  177.             public IBuilder ExecuteOnEnter(Action action) {
  178.                 sourceInfo.enterAction = action;
  179.                 return this;
  180.             }
  181.  
  182.             public IBuilder ExecuteOnLeave(Action action) {
  183.                 sourceInfo.leaveAction = action;
  184.                 return this;
  185.             }
  186.  
  187.             protected internal void Finish() {
  188.                 if (!built) {
  189.                     State source = machine.GetOrCreateState(sourceInfo.stateID);
  190.                     source.EnterAction = sourceInfo.enterAction;
  191.                     source.LeaveAction = sourceInfo.leaveAction;
  192.                     if (sourceInfo.item != null) {
  193.                         source.Item = sourceInfo.item;
  194.                     }
  195.                     foreach (TransitionInfo info in transitions) {
  196.                         Transition transition = new Transition(info.onEventID, machine) {
  197.                             Source = source,
  198.                             Target = machine.GetOrCreateState(info.toStateID)
  199.                         };
  200.                         source.transitions[info.onEventID] = transition;
  201.                     }
  202.                     built = true;
  203.                 }
  204.             }
  205.             #endregion
  206.  
  207.             #region Classes
  208.             private struct StateInfo {
  209.                 public TState stateID;
  210.                 public StateableItem item;
  211.                 public Action enterAction;
  212.                 public Action leaveAction;
  213.             }
  214.  
  215.             private struct TransitionInfo {
  216.                 public TEvent onEventID;
  217.                 public TState toStateID;
  218.             }
  219.             #endregion
  220.         }
  221.         #endregion
  222.  
  223.         #region Interfaces
  224.         public interface IBuilder {
  225.             IBuilder Permit(TEvent onEventID, TState toStateID);
  226.             IBuilder DefineState(StateableItem item);
  227.             IBuilder ExecuteOnEnter(Action action);
  228.             IBuilder ExecuteOnLeave(Action action);
  229.         }
  230.         #endregion
  231.     }
  232.  
  233.     public abstract class StateableItem {
  234.  
  235.         #region Instance Methods
  236.         public virtual void OnEnter() { }
  237.         public virtual void OnLeave() { }
  238.         #endregion
  239.     }
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement