(ns advent.pathfind (:require [play-clj.core :refer :all] [play-clj.ui :refer :all] [play-clj.utils :refer :all] [play-clj.g2d :refer :all] [clojure.pprint] [clojure.data.priority-map :refer [priority-map]]) (:import [com.badlogic.gdx.files FileHandle] [com.badlogic.gdx Files] [com.badlogic.gdx.graphics Camera Color GL20 OrthographicCamera PerspectiveCamera Pixmap Pixmap$Format PixmapIO Texture VertexAttributes$Usage])) (defn printmap [my-map & [skip]] (let [skip (or skip 1)] (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 2) (repeatedly (fn [] (vec (take (/ 320 2) (repeatedly (fn [] (rand-nth [0 0 1 ]))))))))) (update-in [1 1] (constantly 0)) (update-in [50 50] (constantly 0)))) (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 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 2) (* y 2)]) (conj path current-node))) (recur (conj path current-node) (came-from current-node)))))) (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))))) (defn ->scale [loc] (vec (map (fn [x] (int (/ x 2))) loc))) (defn visit-all [my-map play-loc target-loc] (let [play-loc (->scale play-loc) target-loc (->scale 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))))))))) (defn print-resolved [path my-map] (doseq [row (reduce (fn [acc path] (if path (update-in acc (reverse path) (constantly "X")) acc)) my-map path)] (println (map {1 \space 2 "." 0 "W" "X" "X"} row))) nil) (defn map-from-resource [filename] (let [pm (pixmap filename) black (color 0 0 0 255) painful (color 255 0 0 255)] (vec (take-nth 2 (for [y (reverse (range (pixmap! pm :get-height)))] (vec (take-nth 2 (for [x (range (pixmap! pm :get-width)) :let [current-color (color (pixmap! pm :get-pixel x y))]] (cond (color! current-color :equals black) 0 (color! current-color :equals painful) 10 :else 1)))))))))