001 (ns the-great-game.world.routes
002 "Conceptual (plan level) routes, represented as tuples of location ids."
003 (:require [the-great-game.utils :refer [cyclic?]]))
004
005 (defn find-routes
006 "Find routes from among these `routes` from `from`; if `to` is supplied,
007 to `to`, by breadth-first search."
008 ([routes from]
009 (map
010 (fn [to] (cons from to))
011 (remove
012 empty?
013 (map
014 (fn [route]
015 (remove
016 #(= from %)
017 (if (some #(= % from) route) route)))
018 routes))))
019 ([routes from to]
020 (let [steps (find-routes routes from)
021 found (filter
022 (fn [step] (if (some #(= to %) step) step))
023 steps)]
024 (if
025 (empty? found)
026 (find-routes routes from to steps)
027 found)))
028 ([routes from to steps]
029 (if
030 (not (empty? steps))
031 (let [paths (remove
032 cyclic?
033 (mapcat
034 (fn [path]
035 (map
036 (fn [x] (concat path (rest x)))
037 (find-routes routes (last path))))
038 steps))
039 found (filter
040 #(= (last %) to) paths)]
041 (if
042 (empty? found)
043 (find-routes routes from to paths)
044 found)))))
045
046 (defn find-route
047 "Find a single route from `from` to `to` in this `world-or-routes`, which
048 may be either a world as defined in [[the-great-game.world.world]] or else
049 a sequence of tuples of keywords."
050 [world-or-routes from to]
051 (first
052 (find-routes
053 (or (:routes world-or-routes) world-or-routes)
054 from
055 to)))