A style question.
I've got a world data object, which I pass into my functions. It looks
like this:
```clojure
(def world
(atom {:flags #{:want-umbrella}
:location :home
:inventory #{...}
:map {:home {...} :patio {...}))
```
My default describe-room method looks like this:
```clojure
(defmethod describe-room :default [world id]
(let [r (-> world :map id)]
;; TODO: display room contents.
;; TODO: wrap text neatly
(println (:name r))
(println (:description r))))
```
In this function, I retrieve the room using the syntax `(-> world :map
id)`. I might similarly check whether the :want-umbrella flag is set using
the syntax `(-> world :flags :want-umbrella)`. Is that considered good
style? It leaves the structure of the "world" object completely visible,
which could make it hard to change in the future. Would I do better to
define a couple of functions, like this?
```clojure
(defn get-room [world id] (-> world :map id))
(defn flag-set? [world id] (-> world :flags id))
```
Or would that be just complicating things to no good end?
Thanks!
On Thursday, March 29, 2018 at 3:45:02 PM UTC-7, Will Duquette wrote:
>
> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.