Skip to content

Commit c762482

Browse files
committed
2024, day 12
1 parent 822b045 commit c762482

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

2024/12.clj

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(require '[clojure.string :as str]
2+
'[clojure.set :as set])
3+
4+
(def the-map (str/split-lines (slurp "2024/12.in")))
5+
(def unvisited
6+
(set
7+
(for [i (range (count the-map)), j (range (count the-map))]
8+
[i j])))
9+
10+
(def deltas [[0 1] [0 -1] [1 0] [-1 0]])
11+
12+
(defn flood [unvisited position]
13+
(loop [to-visit [position], unvisited unvisited, visited #{}]
14+
(if (empty? to-visit)
15+
visited
16+
(let [visiting (peek to-visit)
17+
to-visit (pop to-visit)]
18+
(recur (into to-visit
19+
(keep (fn [delta]
20+
(let [neighbor (mapv + visiting delta)]
21+
(when (and (contains? unvisited neighbor)
22+
(= (get-in the-map visiting)
23+
(get-in the-map neighbor)))
24+
neighbor)))
25+
deltas))
26+
(disj unvisited visiting)
27+
(conj visited visiting))))))
28+
29+
(def regions
30+
(loop [unvisited unvisited, regions []]
31+
(if (empty? unvisited)
32+
regions
33+
(let [plant (first unvisited), plant-region (flood unvisited plant)]
34+
(recur (set/difference unvisited plant-region)
35+
(conj regions plant-region))))))
36+
37+
(defn perimeter [region]
38+
(reduce (fn [s position]
39+
(into s (keep (fn [delta]
40+
(let [neighbor (mapv + position delta)]
41+
(when-not (contains? region neighbor)
42+
(mapv + position (mapv (partial * 1/4) delta)))))
43+
deltas)))
44+
#{}
45+
region))
46+
47+
;; part 1
48+
(time
49+
(reduce + (map (fn [region] (* (count region) (count (perimeter region)))) regions)))
50+
51+
(defn side->orientation [[i _j]] (if (= (type i) clojure.lang.Ratio) :v :h))
52+
53+
(defn side-from-pos [start perimeter]
54+
(if (= (side->orientation start) :h)
55+
(into #{} cat [(take-while #(contains? perimeter %) (iterate #(update % 0 inc) start))
56+
(take-while #(contains? perimeter %) (iterate #(update % 0 dec) start))])
57+
(into #{} cat [(take-while #(contains? perimeter %) (iterate #(update % 1 inc) start))
58+
(take-while #(contains? perimeter %) (iterate #(update % 1 dec) start))])))
59+
60+
(defn sides [perimeter]
61+
(loop [unvisited perimeter, sides #{}]
62+
(if (empty? unvisited)
63+
sides
64+
(let [start (first unvisited), side (side-from-pos start perimeter)]
65+
(recur (set/difference unvisited side)
66+
(conj sides side))))))
67+
68+
;; part 2
69+
(time
70+
(reduce + (map (fn [region] (* (count region)
71+
(count (sides (perimeter region))))) regions)))

0 commit comments

Comments
 (0)