aoc

ref: master

2020/src/aoc/day04.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
(ns aoc.day04
  (:require [clojure.java.io :as io]
            [clojure.set]))

(def fields #{:byr :iyr :eyr :hgt :hcl :ecl :pid :cid})

(def height-pattern #"(\d+)(cm|in)")

(def hcolor-pattern #"#[a-f0-9]{6}")

(def eye-color-set #{"amb" "blu" "brn" "gry" "grn" "hzl" "oth"})

(def pid-pattern #"\d{9}")

(def validation
  {:byr (fn [v]
          (when (= 4 (count v))
            (let [n (read-string v)]
              (<= 1920 n 2002))))
   :iyr (fn [v]
          (when (= 4 (count v))
            (let [n (read-string v)]
              (<= 2010 n 2020))))
   :eyr (fn [v]
          (when (= 4 (count v))
            (let [n (read-string v)]
              (<= 2020 n 2030))))
   :hgt (fn [v]
          (when-let [[_ digits u] (re-find height-pattern v)]
            (let [n (read-string digits)]
              (case u
                "cm" (<= 150 n 193)
                "in" (<= 59 n 76)))))
   :hcl (fn [v]
          (re-matches hcolor-pattern v))
   :ecl (fn [v]
          (contains? eye-color-set v))
   :pid (fn [v]
          (re-matches pid-pattern v))
   :cid (fn [v] true)})

(def optional-fields (set [:cid]))

(def required-fields
  (clojure.set/difference fields optional-fields))

(defn collect-pair [acc p]
  (let [[k v] (clojure.string/split p #":")]
    (assoc acc (keyword k )v)))

(defn parse-passport [s]
  (let [lines (clojure.string/split-lines s)
        joined (clojure.string/join " " lines)
        pairs (clojure.string/split joined #" ")]
    (reduce collect-pair {} pairs)))

(defn valid? [p]
  (let [pfields (set (keys p))]
    (=
      (clojure.set/intersection required-fields pfields)
      required-fields)))

(defn valid-2? [p]
  (when (valid? p)
    (let [ok (map (fn [field]
                       (let [f (get validation field (constantly true))
                             v (get p field)]
                         (f v)))
                     required-fields)]
       (every? identity ok))))

;; -----------------------------------------------------------------------------

(defn read-input []
  (->> (clojure.string/split (slurp (io/resource "input04.txt")) #"\n\n")
       (map parse-passport)))

(defn compute-1 [input]
  (count
   (filter valid? input)))

(defn compute-2 [input]
  (count
   (filter valid-2? input)))

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