Hello Will. You can simplify it further:
1. Define a multimethod always dispatching by room id. 2. Create a :default implementation. It will be called for non- fancy rooms.3. Create an implementation for :fancy-room. It will be preferred over :default for it. If you ever have a group of rooms with a similar fancy description, use a hierarchy (derive :fancy-room1 :fancy-group) (derive :fancy-room2 :fancy-group) and create an implementation for :fancy-group. Regards, Mikhail. On Mon, 2 Apr 2018, at 19:39, Will Duquette wrote: > Spent the weekend pondering all of this, and here's the way I think I > want to do it.> > 1. The world-state is stored in an atom, and updated much as Gary > Johnson suggests.> > 2. I define a multi-method, (describe-room [room world-state]), that > is responsible for computing the current description of the room: > what it looks like, what items are in it, whatever the player can > currently see or has just noticed.> > 3. The multi-method's dispatch function looks for the :description.> > 3a. If it's a string, the dispatch function returns nil; and I get > the default implementation: it describes the room in the simplest > possible way.> > 3b. If the :description is undefined or nil, the dispatch function > returns the room's id, e.g., :fancy-room. The :fancy-room definition > includes an implementation of the multi-method that's specific to the > :fancy-room. I wouldn't expect to use this approach all that often, > but it should be flexible enough to do anything that comes up.> > 3c. If I find that I have a number of standard flavors for how to > describe a room, I can define the dispatch function accordingly and > add additional implementations.> > There are other ways to skin this cat; but this one seems to give me > maximum simplicity for the normal case, maximum flexibility for > special cases, and it lets me keep all of the logic related to a > single room in one place in the code.> > Comments? > > 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. -- 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.