I'm working on a turn-based game and I'm looking for a good way to manage 
states. In the game each turn is composed of multiple phases. I started by 
using atoms for the phases field (this is a sequence of functions) in a 
record and realized that it wouldn't be ideal to keep track of states in 
the case where I'd need to keep a snapshot of every phases. Here's the 
original code I had:

(defrecord Game [phases]
  (next-phase [this]
    (stop-timer)
    (swap! phases #(conj (vec (rest %)) (first %))) 
    (log :info "change phase to %s" (key (first @phases)))
    (start-phase this))

I then started to think that this would be a good opportunity to use a 
state monad. I've tried to reimplement the above code using the algo.monads 
library but the result was less than satisfactory (probably due to my own 
shortcoming), here's the monadic version:

(defrecord Game [phases]

  (next-phase [this]
    (->
     ((domonad state-m
        [_ (fn [s] (stop-timer) [s s])
         _ (update-state
            (fn [s]
              (update-in s [:phases]
                         #(conj (vec (rest %)) (first %)))))
         _ (fn [s]
             (log :info "change phase to %s" (key (first (:phases s)))) [s s])]
        nil)
      state)
     second
     start-phase))

As my code probably doesn't need the full power of the state monad, I tried 
to write a lighter-weight version using the following macro:

(defmacro >> [& state-and-forms]
  (reduce #(list (if ('#{fn fn*} (first %2))
                   %2
                   `(fn [s#] ~%2 s#)) %)
          state-and-forms))

Which let me write:

  (next-phase [state]
    (>> state
     (stop-timer)
     (fn [s] (update-in s [:phases] #(conj (vec (rest %)) (first %))))
     #(do (log :info "change phase to %s" (key (first (:phases %)))) %)
     #(start-phase %)))

With some more helper macro this version looks promising. In the end I 
wonder if there's some Clojure feature I'm overlooking or if I should 
rethink the whole solution? Is there a better way to accomplish this?


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to