martin
martin

Reputation: 676

Access a global variable by its name in Clojure

I'm trying my hand at a text adventure in clojure.

This is where I am struggling:

(ns records)


(defrecord Room [fdesc sdesc ldesc exit seen])

(defrecord Item [name location adjective fdesc ldesc sdesc flags action ])

(def bedroom (Room. "A lot of text."
                    nil
                    "some text"
                    '(( "west" hallway wearing-clothes? wear-clothes-f))
                    false))

(def hallway (Room. "description of room."
                            nil
                           "short desc of room."
                           '(("east" bedroom) ("west" frontdoor))
                           false))

(def location (ref bedroom))

(defn in?
  "Check if sequence contains item."
  [item lst]
  (some #(= item %) lst))

(defn next-location
  "return the location for a entered direction"
  [direction ] 
  (second (first (filter #(in? direction %) (:exit @location)))))

(defn set-new-location
  "set location parameter to new location."
  [loc]
  (dosync (ref-set location loc)))

My problem is with updating the var location.

If I enter (set-new-location hallway) it works correctly. Location is set to the new room and I can access its fields. However, what I need to do is read the next possible exit from the exit field of a room, but when I enter (set-new-direction (next-exit "west")) location says hallway, but it doesn't point to the variable "hallway".

In CL I'd use (symbol-value hallway). How can I do this in Clojure?

EDIT: I really want to use var-per-location because I have sketched out roughly 30 locations, at 20 lines each, making it too unwieldy to put in one map.

Upvotes: 1

Views: 633

Answers (1)

Michał Marczyk
Michał Marczyk

Reputation: 84331

You can use @(resolve sym) as a symbol-value workalike; what it actually does is look up the Var named by the symbol sym in the current namespace (might be a Var brought in with use / require :refer) and extract its value. See ns-resolve if you want to control the namespace the Var is looked up in.

You could also not use Var-per-location, but rather store your locations in a map somewhere:

(def locations {:hallway ... :bedroom ...})

(You could also put this map in a Ref for convenience of adding new locations at runtime.)

Upvotes: 3

Related Questions