about summary refs log tree commit diff
path: root/day19.clj
blob: 9465025b7403c516350ef36a510095c759c72f2a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(ns org.vuxu.aoc2021.day19
  (:require [clojure.string :as str]
            [clojure.set :as set]))

(def data
  (for [scanner (str/split (slurp "day19") #"\n\n")]
    (->> (str/split-lines scanner)
         (drop 1)
         (map #(str/split % #","))
         (mapv (partial mapv parse-long)))))

(def axes [[0 1 0] [0 -1 0] [1 0 0] [-1 0 0] [0 0 1] [0 0 -1]])

(defn transform [[x y z] up rot]
  (let [[rx ry rz] (case up
                     [ 0  1  0] [x y z]
                     [ 0 -1  0] [x (- y) (- z)]
                     [ 1  0  0] [y x (- z)]
                     [-1  0  0] [y (- x) z]
                     [ 0  0  1] [y z x]
                     [ 0  0 -1] [y (- z) (- x)])]
    (case rot
      0 [rx ry rz]
      1 [rz ry (- rx)]
      2 [(- rx) ry (- rz)]
      3 [(- rz) ry rx])))

(defn translate [p v]
  (mapv + p v))

(defn diff [v1 v2]
  (mapv - v1 v2))

(defn align [beacons1 beacons2]
  (first
   (for [axis axes
         rotation (range 4)
         :let [rotated-beacons2 (map #(transform % axis rotation) beacons2)]
         b1 beacons1
         matching-b1-in-b2 rotated-beacons2
         :let [delta (diff b1 matching-b1-in-b2)
               transformed-beacons2 (set (map #(translate % delta) rotated-beacons2))
               intersection (set/intersection transformed-beacons2 beacons1)]
         :when (>= (count intersection) 12)]
     [transformed-beacons2 delta axis rotation])))

(defn reduc [scans scanners]
  (let [[to-remove scans scanners]
        (loop [to-remove #{}
               scans scans
               scanners scanners
               i 0
               j 1]
          (prn [i j])
          (if (>= i (dec (count scans)))
            [to-remove scans scanners]
            (if (>= j (count scans))
              (recur to-remove scans scanners (inc i) (+ i 2))
              (if (to-remove j)
                (recur to-remove scans scanners i (inc j))
                
                (if-let [[agt trs up rot] (align (scans i) (scans j))]
                  (recur (conj to-remove j)
                         (update scans i set/union agt)
                         (update scanners i set/union
                                 (set (map #(translate trs (transform % up rot)) (scanners j))))
                         i
                         (inc j))
                  (recur to-remove scans scanners i (inc j)))))))]
    [(vec (keep-indexed #(when (not (to-remove %1)) %2) scans))
     (vec (keep-indexed #(when (not (to-remove %1)) %2) scanners))]))

;; very slow :/
(def reducd
  (loop [[scans scanners]
         [(mapv set data) (mapv (constantly #{[0 0 0]}) data)]]
    (if (> (count scans) 1)
      (recur (reduc scans scanners))
      [(first scans)
       (first scanners)])))

(def part1
  (count (first reducd)))
;; => 445

(defn manhattan [a b]
  (apply + (map #(Math/abs %) (diff a b))))

(def part2
  (apply max
         (for [b1 (second reducd)
               b2 (second reducd)]
           (manhattan b1 b2))))
;; => 13225