Skip to content

Instantly share code, notes, and snippets.

@humbhenri
Created December 17, 2020 11:39
Show Gist options
  • Save humbhenri/f57c363c21d81aa8c088d9aa24e35889 to your computer and use it in GitHub Desktop.
Save humbhenri/f57c363c21d81aa8c088d9aa24e35889 to your computer and use it in GitHub Desktop.
(ns p16
(:require [clojure.string :as str]))
(defn to-int[s]
(if (re-matches #"\d+" s)
(Integer/parseInt s)
s))
(defn parse-rule[rule]
(->> rule
(re-matches #"(.*): (\d+)-(\d+) or (\d+)-(\d+)")
rest
(map to-int)
(zipmap [:field :range1-start :range1-end :range2-start :range2-end])))
(defn debug[x]
(println x)
x)
(defn parse-rules [{rules :rules :as notes}]
(->> (map parse-rule (str/split rules #"\n"))
(assoc notes :rules)))
(defn parse-values [{my-ticket :my-ticket nearby-tickets :nearby-tickets :as notes}]
(->> (map #(->> % (re-seq #"\d+") (map to-int)) [my-ticket nearby-tickets])
(zipmap [:my-ticket :nearby-tickets])
(merge notes)))
(defn parse-input [file]
(as-> file x
(slurp x)
(str/split x #"\n\n")
(zipmap [:rules :my-ticket :nearby-tickets] x)
(parse-rules x)
(parse-values x)))
(defn in? [coll elem]
(some #(= elem %) coll))
(defn validate [{r1s :range1-start r1e :range1-end r2s :range2-start r2e :range2-end} value]
(or (in? (range r1s (inc r1e)) value)
(in? (range r2s (inc r2e)) value)))
(defn validate-rules [rules value]
(map #(validate % value) rules))
(defn find-invalid-values [{rules :rules nearby-tickets :nearby-tickets}]
(->> nearby-tickets
(filter #(every? nil? (validate-rules rules %)))))
(defn error-rate [notes]
(->> notes
find-invalid-values
(reduce +)))
(defn transpose [m]
(apply mapv vector m))
(defn positions [{nearby-tickets :nearby-tickets my-ticket :my-ticket}]
(->> (concat my-ticket nearby-tickets)
(partition (count my-ticket))
transpose))
(defn validate-discarding [rule value invalids]
(or (validate rule value)
(in? invalids value)))
(defn find-field [rules values invalids]
(for [r rules
:let [v (map #(validate-discarding r % invalids) values)]
:when (every? (comp not nil?) v)]
(:field r)))
(defn remove-field [field fields]
(cond (not (seq? fields)) fields
(and (= 1 (count fields)) (= field (first fields))) field
:else (remove #(= field %) fields)))
(defn find-single [fields]
(first (first (filter #(and (seq? %) (= 1 (count %))) fields))))
(defn remove-singles [candidates]
(let [single (find-single candidates)]
(if single
(remove-singles (into [] (map #(remove-field single %) candidates)))
candidates)))
(defn find-fields [{rules :rules nearby-tickets :nearby-tickets my-ticket :my-ticket :as notes}]
(let [invalids (find-invalid-values notes)]
(->> notes
positions
(map #(find-field rules % invalids))
remove-singles)))
(defn part2 [notes]
(as-> notes x
(find-fields x)
(zipmap x (:my-ticket notes))
(filter (fn [[k v]] (str/starts-with? k "departure")) x)
(map second x)
(reduce * 1 x)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment