Skip to content

Instantly share code, notes, and snippets.

@damonmcminn
Created February 12, 2017 15:38
Show Gist options
  • Select an option

  • Save damonmcminn/2a863ca09de491e1621333e489f8e460 to your computer and use it in GitHub Desktop.

Select an option

Save damonmcminn/2a863ca09de491e1621333e489f8e460 to your computer and use it in GitHub Desktop.
Garage Door Opener
type FiniteAutomataRule<'State, 'Input> = {
State:'State
Input:'Input
NextState:'State
}
type DoorState =
| Open
| Closed
| Opening
| Closing
| StoppedWhileOpening
| StoppedWhileClosing
| EmergencyOpening
| OpenBlocked
type Input =
| ButtonClicked
| CycleComplete
| BlockDetected
| BlockCleared
type DeterminsticFiniteAutomata (rules, initialState) =
let mutable currentState = initialState
member dfa.State () = currentState
member dfa.NextState input =
let matchesStateAndInput r =
r.State = currentState && r.Input = input
currentState <- (List.find matchesStateAndInput rules).NextState
static member CreateRule (state, input, next) =
{ State = state; Input = input; NextState = next }
static member Cycle rules inputs initialState =
let dfa = DeterminsticFiniteAutomata(rules, initialState)
let printState = printfn "State: %A"
let printInput = printfn "Input: %A"
let mutateAndPrint input =
printInput input
dfa.NextState input |> ignore
printState (dfa.State())
printState (dfa.State())
Seq.iter mutateAndPrint inputs
let doorRules =
[
Open, ButtonClicked, Closing
Closed, ButtonClicked, Opening
Opening, ButtonClicked, StoppedWhileOpening
Closing, ButtonClicked, StoppedWhileClosing
StoppedWhileOpening, ButtonClicked, Closing
StoppedWhileClosing, ButtonClicked, Opening
Opening, CycleComplete, Open
Closing, CycleComplete, Closed
Open, CycleComplete, Open
Closed, CycleComplete, Closed
StoppedWhileOpening, CycleComplete, StoppedWhileOpening
StoppedWhileClosing, CycleComplete, StoppedWhileClosing
]
|> List.map DeterminsticFiniteAutomata.CreateRule
let inputs = [
ButtonClicked
CycleComplete
ButtonClicked
ButtonClicked
ButtonClicked
ButtonClicked
ButtonClicked
CycleComplete
]
let bonusRules =
[
Closing, BlockDetected, EmergencyOpening
EmergencyOpening, ButtonClicked, EmergencyOpening
EmergencyOpening, CycleComplete, OpenBlocked
OpenBlocked, BlockCleared, Open
OpenBlocked, ButtonClicked, OpenBlocked
]
|> List.map DeterminsticFiniteAutomata.CreateRule
let bonusInputs = [
ButtonClicked
CycleComplete
ButtonClicked
BlockDetected
ButtonClicked
CycleComplete
ButtonClicked
BlockCleared
ButtonClicked
CycleComplete
]
printfn "Challenge"
DeterminsticFiniteAutomata.Cycle doorRules inputs Closed
printfn "\n"
printfn "Bonus"
DeterminsticFiniteAutomata.Cycle (doorRules @ bonusRules) bonusInputs Closed
type Complete = Open | Closed
type Stopped = WhileOpening | WhileClosing
type Moving = Opening | Closing
type Input = ButtonClicked | CycleComplete | Blocked
type DoorState =
| Complete of Complete
| Moving of Moving
| Stopped of Stopped
let handleCycleComplete state =
// do nothing if not moving i.e. return state
match state with
| Moving towards ->
match towards with
| Opening -> Complete Open
| Closing -> Complete Closed
| _ -> state
let handleButtonClick state =
match state with
| Complete position ->
match position with
| Open -> Moving Closing
| Closed -> Moving Opening
| Moving towards ->
match towards with
| Opening -> Stopped WhileOpening
| Closing -> Stopped WhileClosing
| Stopped position ->
match position with
| WhileOpening -> Moving Closing
| WhileClosing -> Moving Opening
type GarageDoor () =
let mutable state = Complete Closed
member door.State = state
member door.HandleInput input =
state <-
match input with
| ButtonClicked -> handleButtonClick state
| CycleComplete -> handleCycleComplete state
door.State, input
let inputs = [
ButtonClicked
CycleComplete
ButtonClicked
ButtonClicked
ButtonClicked
ButtonClicked
ButtonClicked
CycleComplete
]
let door = GarageDoor()
let printState = printfn "Door: %A"
let printStateAndInput (state, input) =
printState state
printfn "> %A" input
printState door.State
Seq.iter (door.HandleInput >> printStateAndInput) inputs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment