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 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.