|
| 1 | +;; # Day 1: Trebuchet?! |
| 2 | +;; |
| 3 | + |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +^{:nextjournal.clerk/visibility {:code :hide :result :hide}} |
| 8 | +(ns day01-clerk |
| 9 | + {:nextjournal.clerk/auto-expand-results? true} |
| 10 | + (:require aoc |
| 11 | + [clojure.string :as str] |
| 12 | + [nextjournal.clerk :as clerk])) |
| 13 | + |
| 14 | +;; ## Loading the data |
| 15 | + |
| 16 | +;; Let's load both the example input and the real one: |
| 17 | +(def example-input (aoc/read-file "01_test")) |
| 18 | +(def input (aoc/read-file 1)) |
| 19 | + |
| 20 | +;; Parsing the input is easy, just split the lines of the input: |
| 21 | +(def example-data (aoc/parse-input example-input)) |
| 22 | +(def data (aoc/parse-input input)) |
| 23 | + |
| 24 | + |
| 25 | +;; ## Helpers |
| 26 | +;; |
| 27 | +;; For Part 2, the numbers can be spelled out with letters. |
| 28 | +;; We'll convert them back to digits with the following mappping: |
| 29 | +(def words |
| 30 | + {"one" "1" |
| 31 | + "two" "2" |
| 32 | + "three" "3" |
| 33 | + "four" "4" |
| 34 | + "five" "5" |
| 35 | + "six" "6" |
| 36 | + "seven" "7" |
| 37 | + "eight" "8" |
| 38 | + "nine" "9"}) |
| 39 | + |
| 40 | + |
| 41 | +;; Now, the regex pattern to match either numbers as words or plain numbers: |
| 42 | +(def word-pattern (str/join "|" (keys words))) |
| 43 | +(def first-patt (re-pattern (str word-pattern #"|\d"))) |
| 44 | + |
| 45 | +;; For Part 2, we need to have these word patterns backwards: |
| 46 | +(def last-patt (re-pattern (str (str/reverse word-pattern) #"|\d"))) |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +;; ## Calculate calibration value |
| 51 | + |
| 52 | +;; To calculate the calibration value, we need to find the first and |
| 53 | +;; the last number in a line and concat them togeter: |
| 54 | +(defn calibration-value [line patt rev-patt] |
| 55 | + (let [first-match (re-find patt line) |
| 56 | + last-match (str/reverse (re-find rev-patt (str/reverse line))) |
| 57 | + first-digit (words first-match first-match) |
| 58 | + last-digit (words last-match last-match)] |
| 59 | + (parse-long (str first-digit last-digit)))) |
| 60 | + |
| 61 | +;; For example: |
| 62 | +(def data-sample (take 10 data)) |
| 63 | +(clerk/table {"line" data-sample |
| 64 | + "p1 score" (mapv #(calibration-value % #"\d" #"\d") data-sample) |
| 65 | + "p2 score" (mapv #(calibration-value % first-patt last-patt) data-sample)}) |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | +;; We need to take a sum of a calibration value of each line: |
| 72 | +(defn calibration-sum [lines patt rev-patt] |
| 73 | + (aoc/sum-map #(calibration-value % patt rev-patt) lines)) |
| 74 | + |
| 75 | + |
| 76 | + |
| 77 | +;; ## Putting it all together: |
| 78 | +(defn solve [input] |
| 79 | + (let [lines (aoc/parse-input input)] |
| 80 | + [(calibration-sum lines #"\d" #"\d") |
| 81 | + (calibration-sum lines first-patt last-patt)])) |
| 82 | + |
| 83 | +(solve input) |
0 commit comments