Skip to content

Instantly share code, notes, and snippets.

@pabloogc
Created July 11, 2015 15:12
Show Gist options
  • Save pabloogc/fa8d7bb9f074d6c9768b to your computer and use it in GitHub Desktop.
Save pabloogc/fa8d7bb9f074d6c9768b to your computer and use it in GitHub Desktop.
import java.util.ArrayList
public class StateMachine<S, T>(
private var stateObject: State<S, T>,
private var states: List<State<S, T>>
) {
public val state: S
get() = stateObject.value
public fun move(input: T) {
stateObject.transitions.forEach { t ->
val (function, newState) = t
if (function.invoke(input)) {
stateObject = newState;
return
}
}
throw IllegalStateException("Transition from state '${stateObject.value}' not defined for the input '${input}'")
}
public fun reset() {
stateObject = states[0]
}
}
public class State<S, T>(
public val value: S,
public val transitions: MutableList<Pair<Function1<T, Boolean>, State<S, T>>>) {
}
public fun stateMachine<S, T>(init: StateMachineBuilder<S, T>.() -> Unit): StateMachine<S, T> {
val builder = StateMachineBuilder<S, T>(ArrayList())
builder.init()
return builder.build()
}
public class StateMachineBuilder<S, T>(
private val states: MutableList<StateBuilder<S, T>>
) {
fun state(value: S, transitions: StateBuilder<S, T>.() -> Unit): StateBuilder<T> {
val s = StateBuilder<S, T>(value, ArrayList())
s.transitions()
states.add(s)
return s;
}
fun build(): StateMachine<S, T> {
val linkedStates = ArrayList<State<S, T>>(states.size())
if (states.isEmpty()) throw IllegalStateException("At least one state is required")
states.forEach { s ->
val ref = linkedStates.firstOrNull { ls -> ls.value == s.value }
if (ref != null)
throw IllegalStateException("State '${s.value} already declared")
linkedStates.add(State(s.value, ArrayList<Pair<Function1<T, Boolean>, State<S, T>>>()))
}
for (i in states.indices) {
states[i].transitions.forEach { t ->
val ref = linkedStates.firstOrNull { ls -> ls.value == t.second }
?: throw IllegalStateException("Error in '${states[i].value}'. State '${t.second}' does not exist.")
linkedStates[i].transitions.add(Pair(t.first, ref))
}
}
return StateMachine(linkedStates[0], linkedStates)
}
}
public class StateBuilder<S, T>(
val value: S,
val transitions: MutableList<Pair<(T) -> Boolean, S>>
) {
fun moveIf(next: S, predicate: (T) -> Boolean) {
transitions.add(Pair(predicate, next));
}
fun moveEq(next: S, funcValue: () -> T) {
moveIf(next, { t -> t.equals(funcValue()) })
}
fun move(next: S) {
moveIf(next, { true })
}
fun loopIf(predicate: (T) -> Boolean) {
moveIf(value, predicate)
}
fun loopEq(predicate: () -> T) {
moveEq(value, predicate)
}
fun loop() {
moveIf(value, { true })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment