(ns advent.action-test2 (:require [clojure.core.async :refer [put! ! chan go take! alts!!]])) (defprotocol IAction (begin [this state]) (done? [this state]) (continue [this state]) (terminate [this state])) (defmacro do-actions [name & forms] `(vector ~@(for [form forms] `(fn [~name] ~form)))) (defn talk [action-channel who text] (let [c (chan)] (put! action-channel (reify IAction (begin [this state] (println "Speaking:" text) (assoc state :time 0)) (continue [this state] (Thread/sleep 200) (assoc state :time (inc (:time state)))) (done? [this {:keys [time]}] (< 3 time)) (terminate [this state] (put! c state) state))) c)) (defn give-item [action-channel item] (let [c (chan)] (put! action-channel (reify IAction (begin [this state] (println "Receiving item:" item) (update-in state [:items] #(conj % item))) (continue [this state] state) (done? [this state] true) (terminate [this state] (put! c state) state))) c)) (defn walk-to [action-channel who & targets ] (let [c (chan)] (doseq [[target-x target-y] targets] (put! action-channel (reify IAction (begin [this state] (println "Starting Walking to" target-x target-y) state) (continue [this {:keys [x y] :as state}] (println "Continue Walking from" x y) (Thread/sleep 500) (assoc state :x (inc x) :y (inc y))) (done? [this {:keys [x y]} ] (and (>= x target-x) (>= y target-y))) (terminate [this state] (put! c state) state)))) c)) (defn run-script [state action-channel] (let [random-loc (+ 3 (rand-int 10))] (go (if (= 1 (rand-int 2)) (! action-channel :end)))) (defn test-run [] (let [state {:x 0 :y 0 :time 0 :items #{} :current-action nil} action-channel (chan) actions (run-script state action-channel)] (loop [state state current-action nil started? false] (if (= :end current-action) nil (if current-action (let [state (if started? state (begin current-action state)) state (continue current-action state)] (if (done? current-action state) (recur (terminate current-action state) nil false) (recur state current-action true))) (let [[current-action _] (alts!! [action-channel] :default nil)] (do (Thread/sleep 50) (recur state current-action false))))))))