Skip to content

Instantly share code, notes, and snippets.

@coldnew
Forked from gamma235/elevator-state-machine.clj
Created October 27, 2015 15:35
Show Gist options
  • Save coldnew/bb5bf23b81ef1d46d693 to your computer and use it in GitHub Desktop.
Save coldnew/bb5bf23b81ef1d46d693 to your computer and use it in GitHub Desktop.
(ns jsync.elevator
(:refer-clojure :exclude [map reduce into partition partition-by take merge])
(:require [clojure.core.async :refer :all :as async]))
;; This is necessary to check and see what is on the persistent queue
(defmethod print-method clojure.lang.PersistentQueue
[q, w]
(print-method '<- w)
(print-method (seq q) w)
(print-method '-< w))
;; setting up the management tools for state
(def elevator (atom {}))
(def presses (chan))
(def move-requests (atom clojure.lang.PersistentQueue/EMPTY))
(def update (partial swap! elevator assoc))
;; gives the elevator a starting value
(defn start []
(reset! elevator {:floor 1 :pressed-1 false :pressed-2 false :open true}))
;; main function to put the elevator in various states. Println is for debugging. Only runs when queue has count of 1.
(defn move-elevator []
(cond
(and (= (count @move-requests) 1) (:pressed-1 @elevator))
(do
(update :floor 1)
(update :pressed-1 false)
(println "door open")
(update :open true)
(Thread/sleep 5000)
(println "door closed")
(update :open false)
(update :floor 2)
(println "second floor")
(println "door open")
(update :open true)
(Thread/sleep 5000)
(println "door closed")
(update :open false)
(println "first floor")
(update :floor 1)
(println "done")
(swap! move-requests pop))
(and (< (count @move-requests) 2) (:pressed-2 @elevator))
(do
(update :floor 2)
(update :pressed-2 false)
(println "door open")
(update :open true)
(Thread/sleep 5000)
(println "door closed")
(update :open false)
(update :floor 1)
(println "first floor")
(println "door open")
(update :open true)
(println "done")
(swap! move-requests pop))
(and (false? (:pressed-1 @elevator)) (false? (:pressed-2 @elevator)))
(start))
(if (or (:pressed-1 @elevator) (:pressed-2 @elevator)) (recur)))
;; continuously listens for button presses on the presses channel with a go-loop
(defn listen-for-presses []
(go-loop []
(when-let [p (<! presses)]
(if
(= p :up)
(update :pressed-1 true)
(update :pressed-2 true))
(move-elevator)
(recur))))
;; starting the machine up with default values and a listener
(defn init []
(start)
(listen-for-presses)
(reset! move-requests clojure.lang.PersistentQueue/EMPTY))
;; main api functions, called by elevtor users via pressing buttons outside the doors
(defn move-up []
(if (and (< (count @move-requests) 2) (not (some :move-up @move-requests)))
(do (>!! presses :up)
(swap! move-requests conj :move-up))))
(defn move-down []
(if (and (< (count @move-requests) 2) (not (some :move-down @move-requests)))
(do (>!! presses :down)
(swap! move-requests conj :move-down))))
;; Testing it out
@elevator
(init)
(move-up)
(move-down)
@move-requests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment