aoc

ref: master

2020/src/aoc/day11.clj


  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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
(ns aoc.day11
  (:require [clojure.java.io :as io]))

(def example "L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL")

(declare parse-floor)

(defn read-input []
  (->>
   (io/resource "input11.txt")
   slurp

       ;; example
   clojure.string/split-lines
   parse-floor))

(defn adjacent [m [sx sy]]
  (for [x [-1 0 1]
        y [-1 0 1]
        :when (not= [x y] [0 0])]
    (let [fx (+ x sx)
          fy (+ y sy)]
      [[fx fy] (get m [fx fy] :empty)])))

(defn visible [m [sx sy]]
  (for [x [-1 0 1]
        y [-1 0 1]
        :when (not= [x y] [0 0])]
    (let [fx (+ x sx)
          fy (+ y sy)]
      (some (fn [[[x y] spot]]
              (#{:taken :empty} spot))
            (map (fn [[a b]]
                   [[a b] (get m [a b] :empty)])
                 (rest (iterate
                        (fn [[xx yy]] [(+ xx x) (+ yy y)])
                        [sx sy])))))))

(defn taken-adjacent [m [sx sy]]
  (filter #(= :taken (second %))
          (adjacent m [sx sy])))

(defn taken-visible [m [sx sy]]
  (filter #(= :taken %)
          (visible m [sx sy])))

(defn parse-floor [input]
  (into {}
        (for [y (range (count input))
              x (range (count (first input)))]
          (let [spot (get-in input [y x])
                tile (case spot
                       \L :empty
                       \# :taken
                       \. :floor)]
            [[x y] tile]))))

(defn run [input]
  (into {} (map (fn [[[x y] seat]]
                  (let [taken-count (count (taken-adjacent input [x y]))]
                    (case seat
                      :empty [[x y] (if (zero? taken-count) :taken :empty)]
                      :taken [[x y] (if (>= taken-count 4) :empty :taken)]
                      [[x y] seat])))
                input)))

(defn run-2 [input]
  (into {} (map (fn [[[x y] seat]]
                  (let [taken-count (count (taken-visible input [x y]))]
                    (case seat
                      :empty [[x y] (if (zero? taken-count) :taken :empty)]
                      :taken [[x y] (if (>= taken-count 5) :empty :taken)]
                      [[x y] seat])))
                input)))

(defn reduce-1 [input]
  (loop [input input]
    (let [res (run input)]
      (if (= input res)
        res
        (recur res)))))

(defn reduce-2 [input]
  (loop [input input]
    (let [res (run-2 input)]
      (if (= input res)
        res
        (recur res)))))

(defn compute-1 [input]
  (->> input
       reduce-1
       vals
       frequencies
       :taken))

(defn compute-2 [input]
  (->> input
       reduce-2
       vals
       frequencies
       :taken))

(defn main []
  (let [input (read-input)]
    (println (compute-1 input))
    (println (compute-2 input))))

(main)