src/state/StateTransitionMatrix.ts (71 lines of code) (raw):
import { IStateBase } from "./interfaces/IStateBase";
import { State } from "./State";
import { CustomState } from "./state/CustomState";
import { EarthState } from "./state/EarthState";
import { GravityTraversingState } from "./state/GravityTraversingState";
import { InteractiveWaitingState } from "./state/InteractiveWaitingState";
import { StateBase } from "./state/StateBase";
import { TraversingState } from "./state/TraversingState";
import { WaitingState } from "./state/WaitingState";
type StateCreators = Map<string, new (state: IStateBase) => StateBase>;
export class StateTransitionMatrix {
private readonly _creators: StateCreators;
private readonly _transitions: Map<string, string[]>;
constructor() {
const custom = State[State.Custom];
const earth = State[State.Earth];
const gravityTraverse = State[State.GravityTraversing];
const traverse = State[State.Traversing];
const wait = State[State.Waiting];
const waitInteractively = State[State.WaitingInteractively];
this._creators = new Map();
const creator = this._creators;
creator.set(custom, CustomState);
creator.set(earth, EarthState);
creator.set(gravityTraverse, GravityTraversingState);
creator.set(traverse, TraversingState);
creator.set(wait, WaitingState);
creator.set(waitInteractively, InteractiveWaitingState);
this._transitions = new Map();
const transitions = this._transitions;
transitions.set(custom, [earth, gravityTraverse, traverse]);
transitions.set(earth, [custom, gravityTraverse, traverse]);
transitions.set(gravityTraverse, [custom, earth, traverse, wait, waitInteractively]);
transitions.set(traverse, [custom, earth, gravityTraverse, wait, waitInteractively]);
transitions.set(wait, [gravityTraverse, traverse, waitInteractively]);
transitions.set(waitInteractively, [gravityTraverse, traverse, wait]);
}
public getState(state: StateBase): State {
if (state instanceof CustomState) {
return State.Custom;
} else if (state instanceof EarthState) {
return State.Earth;
} else if (state instanceof GravityTraversingState) {
return State.GravityTraversing;
} else if (state instanceof TraversingState) {
return State.Traversing;
} else if (state instanceof WaitingState) {
return State.Waiting;
} else if (state instanceof InteractiveWaitingState) {
return State.WaitingInteractively;
}
throw new Error("Invalid state instance");
}
public generate(state: State, options: IStateBase): StateBase {
const concreteState = this._creators.get(State[state]);
return new concreteState(options);
}
public transition(state: StateBase, to: State): StateBase {
if (!this.validate(state, to)) {
throw new Error("Invalid transition");
}
return this.generate(to, state);
}
public validate(state: StateBase, to: State): boolean {
const source = State[this.getState(state)];
const target = State[to];
const transitions = this._transitions;
return transitions.has(source) &&
transitions.get(source).includes(target);
}
}