Skip to content

Instantly share code, notes, and snippets.

@vanadium23
Created December 5, 2024 07:58
Show Gist options
  • Save vanadium23/92208a48533a7c70100d74de257d3a55 to your computer and use it in GitHub Desktop.
Save vanadium23/92208a48533a7c70100d74de257d3a55 to your computer and use it in GitHub Desktop.
(ns advent-of-code.day05
(:require [clojure.string :as str]
[clojure.java.io :as io]
[clojure.math.combinatorics :as combo]))
(defn read-input [file]
(str/trim (slurp file)))
(defn to-blocks
"Turn a blob (probably from `slurp`) into a seq of blocks"
[input]
(str/split input #"\n\n"))
(defn parse-out-longs
"Parse out all numbers in `line` that are integers (longs)"
[line]
(vec (map parse-long (re-seq #"[-+]?\d+" line))))
(defn to-lines
"Turn a blob or block into a seq of lines"
[input]
(str/split-lines input))
(defn parse-line
"Parse a line into a seq of strings"
[line]
(vec (map parse-long (str/split line #"\|"))))
(defn index-of [v n]
(first (keep-indexed (fn [i x] (when (= x n) i)) v)))
(defn apply-rule [nums [less great]] (let [less-index (index-of nums less)
great-index (index-of nums great)]
(if (and less-index great-index)
(if (< less-index great-index) true false)
true)))
(defn is-correct-nums [nums rules] (every? true? (map #(apply-rule nums %) rules)))
(defn middle-index [v]
(if (empty? v)
nil
(quot (count v) 2)))
(defn middle-value [v]
(when (seq v)
(nth v (middle-index v))))
(defn part1 [input] (let [blocks (to-blocks input)
lines (to-lines (first blocks))
parsed (map parse-line lines)
nums (map parse-out-longs (to-lines (second blocks)))
correct-nums (filter #(is-correct-nums % parsed) nums)]
(reduce + (map middle-value correct-nums))))
;; brute force approach (21! permutations)
(defn correct-order [nums rules]
(let [combos (combo/permutations nums)]
(first (filter #(is-correct-nums % rules) combos))))
(defn swap-by-values [vec [val1 val2]]
(let [idx1 (.indexOf vec val1)
idx2 (.indexOf vec val2)]
(if (and (not= idx1 -1) (not= idx2 -1))
(-> vec
(assoc idx1 val2)
(assoc idx2 val1))
vec)))
;; swap by values until right
(defn correct-order-optimized [nums rules] (
loop [acc nums]
(if (is-correct-nums acc rules)
acc
(recur (swap-by-values acc (first (filter #(not (apply-rule acc %)) rules))))
)
))
(defn part2 [input] (let [blocks (to-blocks input)
lines (to-lines (first blocks))
parsed (map parse-line lines)
nums (map parse-out-longs (to-lines (second blocks)))
incorrect-nums (filter #(not (is-correct-nums % parsed)) nums)]
(reduce + (map middle-value (map #(correct-order-optimized % parsed) incorrect-nums)))))
(def answer1example (part1 (read-input "05-example.txt")))
(assert (= answer1example 143) answer1example)
(def answer1 (part1 (read-input "05.txt")))
(assert (= answer1 5762) answer1)
(def answer2example (part2 (read-input "05-example.txt")))
(assert (= answer2example 123) answer2example)
(def answer2 (part2 (read-input "05.txt")))
(assert (= answer2 0) answer2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment