diff --git a/desktop/src-common/advent/pathfind.clj b/desktop/src-common/advent/pathfind.clj index 3ce1c1b0..f85fc743 100644 --- a/desktop/src-common/advent/pathfind.clj +++ b/desktop/src-common/advent/pathfind.clj @@ -7,6 +7,7 @@ [clojure.data.priority-map :refer [priority-map]]) (:import [com.badlogic.gdx.files FileHandle] [com.badlogic.gdx Files] + [java.lang Math] [com.badlogic.gdx.graphics Camera Color GL20 OrthographicCamera PerspectiveCamera Pixmap Pixmap$Format PixmapIO Texture VertexAttributes$Usage])) @@ -16,63 +17,71 @@ (doseq [row (take-nth skip my-map)] (println (take-nth skip (map {1 \space 0 "W" "X" "X" "." "."} row)))))) -(defn random-map [] (-> (vec (take (/ 240 4) (repeatedly (fn [] (vec (take (/ 320 4) (repeatedly (fn [] (rand-nth [1 1 1 1 1 5 0]))))))))) +(defn random-map [] (-> (vec (take (/ 240 4) (repeatedly (fn [] (vec (take (/ 320 4) (repeatedly (fn [] (rand-nth [1 1 1 5 5 0]))))))))) (update-in [1 1] (constantly 1)) (update-in [50 50] (constantly 1)))) -(defn neighbors [[x y] my-map] - (let [candidates [[(dec x) (dec y)] [x (dec y)] [(inc x) (dec y)] - [(dec x) y] [(inc x) y] - [(dec x) (inc y)] [x (inc y)] [(inc x) (inc y)]]] - (remove #(= 0 (get-in my-map (reverse %))) - (filter (fn [[x y]] (and (< -1 x (count (first my-map))) - (< -1 y (count my-map)))) candidates)))) +(defn neighbors [[^long x ^long y] my-map] + (let [candidates [[^long (dec x) ^long (dec y)] [x ^long (dec y)] [^long (inc x) ^long (dec y)] + [^long (dec x) y] [^long (inc x) y] + [^long (dec x) ^long (inc y)] [x ^long (inc y)] [^long (inc x) ^long (inc y)]] + width (count (first my-map)) + height (count my-map)] + (vec (remove #(= 0 (get-in my-map (reverse %))) + (filter (fn [[x y]] (and (< -1 x width) + (< -1 y height))) candidates))))) (defn resolve-path [came-from play-loc target-loc] - (if (nil? (came-from target-loc)) - nil - (loop [path [] - current-node target-loc] - (if (or (= current-node play-loc) - (nil? current-node)) - (reverse (map (fn [[x y]] [x y]) (conj path current-node))) - (recur - (conj path current-node) - (came-from current-node)))))) + (let [came-from (into {} came-from)] -(defn heuristic [[goal-x goal-y] [current-x current-y]] - (let [dist-x (Math/abs (- goal-x current-x )) - dist-y (Math/abs (- goal-y current-y)) - d2 (Math/sqrt 2)] - (+ dist-x dist-y (* (- d2 1) - (min dist-x dist-y))))) + + (if (nil? (came-from target-loc)) + nil + (loop [path [] + current-node (vec target-loc)] + (if (or (= current-node play-loc) + (nil? current-node)) + (reverse (map (fn [[x y]] [x y]) (conj path current-node))) + (recur + (conj path current-node) + (came-from (vec current-node)))))))) + +(def d2 ^double (- (Math/sqrt 2) 1)) +(defn heuristic [^long goal-x ^long goal-y ^long current-x ^long current-y] + (let [dist-x ^long (if (< goal-x current-x) + ^long (- current-x goal-x) + ^long (- goal-x current-x )) + dist-y ^long (if (< goal-y current-y) + ^long (- current-y goal-y) + ^long (- goal-y current-y))] + ^long (+ dist-x dist-y (* ^double d2 + ^long (min dist-x dist-y))))) (defn visit-all [my-map play-loc target-loc] - (if (= 0 (get-in my-map (reverse target-loc))) - nil - (loop [cost-so-far {play-loc 0} - came-from {} - fronteir (priority-map play-loc 0)] - (let [current-loc (first (keys fronteir))] - (if (or (empty? fronteir) - (= current-loc target-loc)) - (resolve-path came-from play-loc target-loc) - (let [neighbors (neighbors current-loc my-map) - [cost-so-far came-from fronteir] (reduce (fn [[cost-so-far came-from fronteir] neighbor] - (let [new-cost (+ (cost-so-far current-loc) (get-in my-map (reverse neighbor)))] - (if (or (nil? (cost-so-far neighbor)) - (< new-cost (cost-so-far neighbor))) - [(assoc cost-so-far neighbor new-cost) - (assoc came-from neighbor current-loc) - (assoc fronteir neighbor (+ new-cost (heuristic target-loc neighbor)))] - [cost-so-far came-from fronteir] - ))) - [cost-so-far came-from fronteir] - neighbors)] - - (recur cost-so-far came-from (dissoc fronteir current-loc)))))))) + (let [play-loc (vec play-loc) + target-log (vec target-loc)] + (if (= 0 (get-in my-map (reverse target-loc))) + nil + (let [cost-so-far ^java.util.HashMap (java.util.HashMap. {play-loc 0}) + came-from ^java.util.HashMap (java.util.HashMap.) + fronteir ^java.util.PriorityQueue (java.util.PriorityQueue. 100 (comparator (fn [a b] (< (:cost a) (:cost b)))))] + (.offer fronteir {:cost 0 :loc play-loc}) + (loop [current-loc (.poll fronteir)] + (if (or (nil? current-loc) + (= (:loc current-loc) target-loc)) + (resolve-path came-from play-loc target-loc) + (do (doseq [neighbor (neighbors (:loc current-loc) my-map)] + (let [cost-for-neighbor (.get cost-so-far neighbor) + new-cost (+ (.get cost-so-far (:loc current-loc)) (get-in my-map (reverse neighbor)))] + (when (or (nil? cost-for-neighbor) + (< new-cost cost-for-neighbor)) + (.put came-from (vec neighbor) (vec (:loc current-loc))) + (.put cost-so-far (vec neighbor) new-cost) + (.offer fronteir {:cost (+ new-cost (heuristic (first target-loc) (second target-loc) (first neighbor) (second neighbor))) + :loc neighbor})))) + (recur (.poll fronteir))))))))) (defn print-resolved [path my-map] @@ -87,8 +96,11 @@ nil) (defn test-pathfind [] - (let [my-map (random-map)] - (print-resolved (visit-all my-map [1 1] [50 50]) my-map))) + (let [my-map (random-map) + path (visit-all my-map [1 1] [50 50])] + (println "Test") + (print-resolved path my-map) + (println path))) (defn map-from-resource [filename] (let [pm (pixmap filename)