Skip to content

Commit 0862c27

Browse files
committed
Solve the day 16 puzzle
1 parent f48a6a5 commit 0862c27

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

day16/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Execute this code via `clj -M -m day16 <filename>`.
2+
3+
### Observations
4+

day16/src/day16.clj

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
(ns day16
2+
(:require [clojure.set :as set]
3+
[clojure.string :as str]
4+
[clojure.java.io :as io]))
5+
6+
(defrecord Cell [north south east west])
7+
8+
(defrecord Config [path path-score])
9+
10+
(defn read-maze [filename]
11+
(defn process-line [y line]
12+
(map-indexed (fn [x e] [[x y] e]) (str/split line #"")))
13+
14+
(defn create-cell [x y mapping]
15+
(defn helper [p] (if (contains? mapping p) p))
16+
(Cell. (helper [x (- y 1)])
17+
(helper [x (+ y 1)])
18+
(helper [(+ x 1) y])
19+
(helper [(- x 1) y])))
20+
21+
(defn find-loc [sym pos-to-sym]
22+
(first (first (filter #(= sym (last %)) pos-to-sym))))
23+
(let [pos-to-sym (with-open [file (io/reader filename)]
24+
(->>
25+
file
26+
(line-seq)
27+
(map-indexed process-line)
28+
(apply concat)
29+
(filter #(#{"." "S" "E"} (last %)))
30+
(into {})))
31+
start-loc (find-loc "S" pos-to-sym)
32+
end-loc (find-loc "E" pos-to-sym)
33+
maze (->>
34+
pos-to-sym
35+
(keys)
36+
(map (fn [[x y]] [[x y] (create-cell x y pos-to-sym)]))
37+
(into {}))]
38+
[maze start-loc end-loc]))
39+
40+
(def directions #{:north :south :east :west})
41+
42+
(defn opposite-of [d]
43+
(case d
44+
:north :south
45+
:south :north
46+
:east :west
47+
:west :east))
48+
49+
(defn solve-part [maze start-loc end-loc]
50+
(defn get-next-positions [[loc dir]]
51+
(->>
52+
(disj directions (opposite-of dir))
53+
(map (fn [d] [(d (maze loc)) d]))
54+
(filter #(some? (first %)))))
55+
56+
(defn make-new-config [pos config pos-to-score]
57+
(let [curr-path (:path config)
58+
curr-dir (second (first curr-path))
59+
new-dir (second pos)]
60+
(Config. (cons pos curr-path)
61+
(+ (:path-score config) (if (= curr-dir new-dir) 1 1001)))))
62+
63+
(defn update-pos-to-score [pos-to-score config]
64+
(let [pos (first (:path config))
65+
pos-score (get pos-to-score pos Integer/MAX_VALUE)
66+
new-score (:path-score config)]
67+
(if (< new-score pos-score)
68+
(assoc pos-to-score pos new-score)
69+
pos-to-score)))
70+
71+
(defn explore-paths [configs pos-to-score end-score best-positions]
72+
(let [config (first configs)
73+
rest-configs (rest configs)
74+
curr-pos (first (:path config))
75+
path-score (:path-score config)]
76+
(if (and (some? end-score) (> path-score end-score))
77+
[end-score best-positions]
78+
(if (= (first curr-pos) end-loc)
79+
(recur rest-configs pos-to-score path-score
80+
(concat best-positions (:path config)))
81+
(if (<= path-score (get pos-to-score curr-pos Integer/MAX_VALUE))
82+
(let [new-configs (->>
83+
(get-next-positions curr-pos)
84+
(map #(make-new-config % config pos-to-score)))]
85+
(recur (sort-by #(:path-score %)
86+
(concat new-configs rest-configs))
87+
(reduce update-pos-to-score pos-to-score new-configs)
88+
end-score best-positions))
89+
(recur rest-configs pos-to-score end-score best-positions))))))
90+
91+
(let [start-pos [start-loc :east]
92+
start-configs [(Config. [start-pos] 1)]
93+
[score best-tiles] (explore-paths start-configs {start-pos 1} nil #{})]
94+
[(- score 1)
95+
(count (distinct (map first best-tiles)))]))
96+
97+
(defn -main [filename]
98+
(let [[maze start-loc end-loc] (read-maze filename)]
99+
(println (solve-part maze start-loc end-loc))))

0 commit comments

Comments
 (0)