Rooms part 1

This week I've started working on the room system for my MUD. My end goal is to generate a small town that players can interacte with.

linkBuilding a zone

A zone is a grouping of multiple rooms and rooms are connected by a direction. I've decided to represent this as an adjacency list (The directional aspect has yet to be implemented).


2(defn add-room-if-absent

3 "Adds a room to the zone if it doesn't exit and returns the entire zone"

4 [zone room]

5 (if (contains? zone room)

6 zone

7 (assoc zone room [])))


9(defn add-exit

10 "adds an exit from one room to another unidirectionally"

11 [zone source-room target-room]

12 (-> zone

13 (add-room-if-absent target-room)

14 (add-room-if-absent source-room)

15 (update-in [source-room] #(conj % target-room))

16 )

17 )

We can then generate our zone like so


1 (def zone (-> {}

2 (add-exit :a :b)

3 (add-exit :b :a)

4 (add-exit :b :e)

5 (add-exit :a :c)

6 (add-exit :c :d)

7 (add-exit :d :e)))

8 => {:b [:a], :a [:b :c], :c [:d], :d [:e], :e []}


I've also implemented the Dijkstra algorithm so that I can easily find the shortest path to Room X from Room Y.

I kept going back and forth on the structure of the data however I'm happy with how it turned out. I felt joy when I finally managed to get it to work.

Furthermore I finally understand the Symmetrizer example in the Brave Clojure book!

1(defn build-graph

2 "Returns a map for each room in the zone identifying the cost it takes to get there from the source-room"

3 [zone source-room]

4 (let [rooms (keys zone)]

5 (loop [results (assoc-in (zipmap rooms (repeat {:cost ##Inf :prev nil})) [source-room :cost] 0)

6 unvisited (set rooms)]

7 (if (empty? unvisited)

8 results

9 (let [current (first (sort-by (comp :cost second) (select-keys results unvisited)))

10 current-room (first current)]

11 (recur

12 (update-costs zone current-room results)

13 (disj unvisited current-room))

14 )

15 )))

16 )


18 (defn update-costs [zone current-room current-costs]

19 "returns an updated dijkstra result map by updating the path to all neighbours of the current-room in the zone"

20 (let [current-cost (get current-costs :cost)

21 neighbours (exits zone current-room)]

22 (reduce (fn [x x1]

23 (as-> x1 v

24 (get current-costs v)

25 {x1 (if (< (inc current-cost) (get v :cost))

26 (assoc v :cost (inc current-cost) :prev current-room) ;

27 v)

28 }

29 (merge x v))

30 )

31 current-costs neighbours)

32 ))

Running the build-graph function returns the following

1 (build-graph zone :a)

2 => {:b {:cost 1, :prev :a}, :a {:cost 0, :prev nil}, :e {:cost 2, :prev :b}, :c {:cost 1, :prev :a}, :d {:cost 2, :prev :c}}


Building a zonePathfindingTodo

Home Rooms part 2 Rooms part 1 This blog's purpose