aoc

ref: master

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

(def example "1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc")

;; https://gist.github.com/edbond/665401
(defmacro xor
  "Evaluates exprs one at a time, from left to right.  If only one form returns
  a logical true value (neither nil nor false), returns true.  If more than one
  value returns logical true or no value returns logical true, retuns a logical
  false value.  As soon as two logically true forms are encountered, no
  remaining expression is evaluated.  (xor) returns nil."
  ([] nil)
  ([f & r]
     `(loop [t# false f# '[~f ~@r]]
        (if-not (seq f#) t#
                (let [fv# (eval (first f#))]
                  (cond
                   (and t# fv#) false
                   (and (not t#) fv#) (recur true (rest f#))
                   :else (recur t# (rest f#))))))))

(defn parse-line [line]
  (zipmap [:min :max :letter :password]
          (rest
            (re-find #"(\d+)-(\d+) (\w): (\w+)" line))))

(defn string-to-char [s]
  (first (char-array s)))

(defn password-valid? [p]
  (let [min          (read-string (:min p))
        max          (read-string (:max p))
        freqs        (frequencies (:password p))
        letter       (string-to-char (:letter p))
        letter-count (get freqs letter 0)]
    (and
     (>= letter-count min)
     (<= letter-count max))))

(defn password-valid-2? [p]
  (let [pass (:password p)
        idx-1 (get pass (dec (read-string (:min p))))
        idx-2 (get pass (dec (read-string (:max p))))
        letter (string-to-char (:letter p))]
    (xor
     (= idx-1 letter)
     (= idx-2 letter))))

(defn check-passwords [acc val]
  (if (password-valid? val)
    (inc acc)
    acc))

(defn check-passwords-2 [acc val]
  (if (password-valid-2? val)
    (inc acc)
    acc))

;; ----

(defn read-input []
  (->> (io/resource "input02.txt")
       slurp
       clojure.string/split-lines
       (map parse-line)))

(defn compute-1 [input]
  (reduce check-passwords 0 input))

(defn compute-2 [input]
  (reduce check-passwords-2 0 input))

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