我正在尝试在clojure中实现A *搜索算法(尚未完成):
(ns typedclj.rhizome
(:require [clojure.set :refer [union]]))
(use 'clojure.pprint)
(defmacro epprint [expr]
`(do (pprint '~expr)
(pprint ~expr)))
(defmacro epprints [& exprs]
(list* 'do (map (fn [x] (list 'epprint x))
exprs)))
(epprints (inc 1) (inc 2))
(def world [[1 1 1 1 1]
[999 999 999 999 1]
[1 1 1 1 1]
[1 999 999 999 999]
[1 1 1 1 1]])
(def ^:dynamic *world-size* 5)
(def ^:dynamic *step-cost* 900)
;(alter-var-root #'*world-size* (constantly 5))
(defn neighbors
([yx]
(neighbors [[-1 0] [1 0] [0 -1] [0 1]] *world-size* yx))
([deltas *world-size* yx]
(filter (fn [new-yx] (every? #(< -1 % *world-size*)
new-yx))
(map #(vec (map + yx %)) deltas))))
(defn heuristic-cost-estimate [[y x]]
(* *step-cost*
(- (+ *world-size* *world-size*) y x 2)))
(defn mapmat [f mat]
(mapv (fn [row]
(mapv f row))
mat))
(defn mapmats [f & mats]
(apply mapv (fn [& rows]
(apply mapv f rows))
mats))
(defn randmat []
(repeatedly *world-size*
(fn [] (repeatedly
*world-size*
#(rand-int 10)))))
(defn min-by [f coll]
(when (seq coll)
(reduce (fn [min this]
(if (> (f min) (f this)) this min))
coll)))
(pprint (randmat))
(let [m1 (randmat)
m2 (randmat)
m3 (randmat)]
(epprints m1 m2 m3)
(mapmats + m1 m2 m3))
(defn constant-matrix [c]
(vec (repeat *world-size*
(vec (repeat *world-size* c)))))
(let [coords (for [i (range *world-size*)]
(for [j (range *world-size*)]
[i j]))
h-score (mapmat heuristic-cost-estimate coords)
start [0 0]
goal-y *world-size*
goal-x goal-y
goal [goal-x goal-y]]
(loop [closedset #{}
openset #{[0 0]}
came-from (constant-matrix [nil nil])
g-score (assoc-in (constant-matrix 1e8) start 0)
f-score (mapmats + g-score h-score)
]
(let [
current (min-by f-score openset)
openset (disj openset current)
closedset (conj closedset current)
nbrs (filter (complement closedset)
(neighbors current))
openset (union openset (set nbrs))
]
(if (empty? openset)
(if (= current goal)
came-from
false)
(let [[came-from g-score f-score]
(reduce (fn [[cf gs fs :as to-be-updated] nbr]
(let [current-g-score (get-in g-score current)
nbr-g-score (get-in g-score nbr)
nbr-cost (get-in world nbr)
tentative-g-score (+ current-g-score
nbr-cost)]
(if (>= tentative-g-score nbr-g-score)
to-be-updated
[(assoc-in cf nbr current)
(assoc-in gs nbr tentative-g-score )
(assoc-in fs nbr (+ tentative-g-score
(get-in h-score nbr)))])))
[came-from g-score f-score]
nbrs)]
(epprints nbrs
openset
came-from
g-score
f-score)
(recur closedset openset came-from g-score f-score))))))
将此加载到repl中时出现了一些奇怪的错误:
CompilerException java.lang.IllegalArgumentException: Key must be integer, compiling:(/Users/kaiyin/personal_config_bin_files/workspace/typedclj/src/typedclj/rhizome.clj:70:48)
我做错了什么?
这是我使用的伪代码(来自维基百科):
function A*(start,goal)
closedset := the empty set // The set of nodes already evaluated.
openset := {start} // The set of tentative nodes to be evaluated, initially containing the start node
came_from := the empty map // The map of navigated nodes.
g_score[start] := 0 // Cost from start along best known path.
// Estimated total cost from start to goal through y.
f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)
while openset is not empty
current := the node in openset having the lowest f_score[] value
if current = goal
return reconstruct_path(came_from, goal)
remove current from openset
add current to closedset
for each neighbor in neighbor_nodes(current)
if neighbor in closedset
continue
tentative_g_score := g_score[current] + dist_between(current,neighbor)
if neighbor not in openset or tentative_g_score < g_score[neighbor]
came_from[neighbor] := current
g_score[neighbor] := tentative_g_score
f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
if neighbor not in openset
add neighbor to openset
return failure
答案 0 :(得分:1)
(defn constant-matrix [c]
(vec (repeat *world-size*
(vec (repeat *world-size* c)))))
第一个repeat
传递一个向量作为第二个参数,向量不是一个数字。