I'm an experienced programmer, but a Clojure newbie; as a beginner project, 
I'm looking into how one would idiomatically write a text adventure of 
sorts in Clojure.  I'm less interested in producing a playable game than I 
am in learning how to do such a thing in a proper functional style.

Suppose in this game I have a room whose description changes based on a 
global flag.  For example, there's something in the Fancy Room that you 
won't notice until you've reached the major plot point.

The world map is (for the sake of argument) a hash-map whose keys are the 
room IDs and whose values are room records, where each record is a hash-map.

(def world {:fancy-room {:name "Fancy Room" :description "This is a fancy 
room." ...}})

I'm aware that I could use a (defstruct) or (defrecord); I'm keeping it 
simple for now.  Then, the flags are saved in a ref; the intent is that 
mutable set is segregated, so that it can more easily be written to a save 
file.

;; Global set of flags
(def flags (ref #{})

(defn flag-set [flag]
   (dosync (alter flags conj flag))

;; When the major plot point is reached
(flag-set :major-plot-point-reached)
 
Normally, to describe a room you just return its :description.

(defn describe [room] (:description (world get room)))

But for the :fancy-room, the returned description depends on the global 
flag, and it will be specific to :fancy-room.  I could add this logic 
directly to the (describe) function's body, but that would be ugly.  What 
I'd like to do is attach a lambda to the :fancy-room in some way.  The 
(describe) function looks for a :describer, and if it's there it calls it; 
and if not it just returns the :description:

(defn describe [entity]
    (if (:describer entity) 
      ((:describer entity) entity)
      (:description entity)))

*Question 1*: this works, but it looks ugly to me; I figure there's a 
better, more idiomatic way to do this kind of thing that's probably obvious 
to anyone with any real experience.  Multimethods, maybe?  Define a Room 
protocol, then let most rooms be NormalRoom records, but let :fancy-room be 
a FancyRoom record?

*Question 2*: Whatever code actually computes the description, it will need 
access to the :major-plot-point-reached flag.  What's the cleanest way to 
give the description code access to the flags ref?  It could simply access 
"@flags" directly:

(if (:major-plot-point-reached @flags) 
  "This is a fancy room.  Hey, that light sconce looks movable!"
  "This is a fancy room.")

But that doesn't seem properly functional.  Would it be better to pass the 
game state into each method?

(defn describe [entity state]
  (if (:describer entity)
     ((:describer entity) entity state)
     (:description entity)))

Any ideas?

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to