Howdy!

Yeah, I get this; and for most of the rooms it's plenty good enough.  It's 
the ones that are complicated that concern me.  Writing text adventures has 
been one of my standard ways of learning new languages, going back to the 
mid-80s to a simple text adventure I wrote—in LISP, actually—on an 8-bit 
CP/M-80 system, so I've a rich appreciation for how complicated things can 
get, and it's that richness I'm wanting to be able to capture.

In OOP terms, I find that most rooms are just Room objects with normal 
semantics; and the ones that aren't are different in different ways.  I 
almost need a new class for each "fancy room".  That's the kind of richness 
I'm looking for.

On Thursday, March 29, 2018 at 4:40:34 PM UTC-7, tbc++ wrote:
>
> You often don't even need functions for this sort of thing. This is what 
> is often called "data driven" programs. Simply define this as a hashmap 
> with :description, :items, etc and then a single function that introspects 
> this data and figures out how to describe the room. 
>
> Also you might want to read up on Entity Component Systems. They are often 
> implemented in OOP languages, but they really are not OOP at all. Here's a 
> good talk on the subject: https://www.youtube.com/watch?v=TW1ie0pIO_E
>
> On Thu, Mar 29, 2018 at 5:00 PM, Will Duquette <wi...@wjduquette.com 
> <javascript:>> wrote:
>
>> Aha!  How about this, to cut the Gordian knot:
>>
>>
>>    1. The fancy room's :description isn't necessarily a simple string.  
>>    It can be a vector of specs, where each spec is a text snippet or a pair 
>>    containing a predicate function and a text snippet.
>>    2. The (describe) function takes two arguments, the global state and 
>>    the room record.
>>    3. It steps through the specs, including only those snippets whose 
>>    predicate is true.  The predicates, of course, are predicates on the 
>> global 
>>    state.
>>
>> The room is then a simple object; and the describe method remains purely 
>> functional.
>>
>> 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 clo...@googlegroups.com 
>> <javascript:>
>> Note that posts from new members are moderated - please be patient with 
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+u...@googlegroups.com <javascript:>
>> 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+u...@googlegroups.com <javascript:>.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
>
> -- 
> “One of the main causes of the fall of the Roman Empire was that–lacking 
> zero–they had no way to indicate successful termination of their C 
> programs.”
> (Robert Firth) 
>

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