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.

Reply via email to