Skip to content

Commit

Permalink
Day 19: Solve part 1 and 2
Browse files Browse the repository at this point in the history
  • Loading branch information
nihas101 committed Dec 19, 2023
1 parent eee81b3 commit f61fde7
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 13 deletions.
112 changes: 109 additions & 3 deletions src/advent_of_code_2023/day19.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,114 @@
(:require
[advent-of-code-2023.utils.string :as u]))

(defn parse-input [input])
(defn- parse-condition [condition]
(let [[p fun comp] (re-seq #"\d+|[^<>=]+|[<>=]" condition)]
[(cond
fun (let [fun (resolve (read-string fun))
y (Long/parseLong comp)]
(fn [part] (fun (part p) y)))
(= p "A") (constantly "A")
(= p "R") (constantly "R")
:else (constantly p))
fun p (if fun (Long/parseLong comp) comp)]))

(defn day19-1 [parsed-input])
(defn- parse-rule [rule]
(let [[condition target] (u/split-sections rule #":")
[cond-fun fun p comp] (parse-condition condition)]
{:condition cond-fun
:fun fun
:p p
:comp comp
:target target}))

(defn day19-2 [parsed-input])
(defn- parse-rules [rules]
(when rules
(mapv parse-rule (u/split-sections rules #","))))

(defn- parse-parts [parts]
(when parts
(mapv (fn [part-ratings]
(transduce
(map (fn [[k v]] [k (Long/parseLong v)]))
conj {} (partition-all 2 (re-seq #"[a-z]+|\d+" part-ratings))))
(u/split-sections parts u/line-endings))))

(defn- parse-line [line]
(let [[workflow rules]
(u/split-sections line #"\{|\}")]
{workflow (parse-rules rules)}))

(defn parse-input [input]
(when input
(let [[wf-input parts] (u/split-sections input)]
{:workflows (transduce
(map parse-line)
merge (u/split-sections wf-input u/line-endings))
:part-ratings (parse-parts parts)})))

(defn- run-workflow [workflow part-rating]
(loop [[{:keys [condition target]} & wf] workflow]
(let [result (condition part-rating)]
(cond
(string? result) result
result target
:else (recur wf)))))

(defn- workflow [workflows]
(fn [part-rating workflow]
(let [next-workflow (run-workflow (workflows workflow) part-rating)]
(cond
(#{"R" "A"} next-workflow) (= "A" next-workflow)
(string? next-workflow) (recur part-rating next-workflow)
(keyword? next-workflow) next-workflow))))

(defn day19-1 [{:keys [workflows part-ratings]}]
(transduce
(comp
(filter #((workflow workflows) % "in"))
(map (juxt #(get % "x") #(get % "m") #(get % "a") #(get % "s")))
(map (partial reduce +)))
+ part-ratings))

(defn- shorten-range-left [[^long a ^long b] ^long c]
[(max a c) b])

(defn- shorten-range-right [[^long a ^long b] ^long c]
[a (min b c)])

(defn- split-range [part-rating-ranges fun p ^long comp]
(condp = fun
"<" [(update part-rating-ranges p shorten-range-left comp)
(update part-rating-ranges p shorten-range-right (dec comp))]
">" [(update part-rating-ranges p shorten-range-right comp)
(update part-rating-ranges p shorten-range-left (inc comp))]))

(defn combinations-count [ranges]
(transduce
(map (fn [[^long mi ^long ma]] (- (inc ma) mi)))
* (vals ranges)))

(defn- valid-input-ranges [wf-name
[{:keys [fun p comp target]} & wfs]
workflows
part-rating-ranges]
(cond
(= wf-name "A") [part-rating-ranges]
(= wf-name "R") []
fun (let [[wf-false wf-true] (split-range part-rating-ranges fun p comp)]
(into (valid-input-ranges wf-name wfs
workflows wf-false)
(valid-input-ranges target (workflows target)
workflows wf-true)))
p (recur p (workflows p) workflows part-rating-ranges)))

(defn day19-2 [{:keys [workflows]}]
(transduce
(map combinations-count)
+ (valid-input-ranges "in"
(workflows "in")
workflows
{"x" [1 4000]
"m" [1 4000]
"a" [1 4000]
"s" [1 4000]})))
2 changes: 1 addition & 1 deletion src/advent_of_code_2023/utils/graph.clj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
visited visited
path-val (path-fn)]
(let [[c] (first q)
q (if (seq q) (pop q) nil)]
q (when (seq q) (pop q))]
(cond
(continue? c) (let [nz (neighbours c visited)]
(recur (reduce assoc-to-priority-map q nz)
Expand Down
30 changes: 21 additions & 9 deletions test/advent_of_code_2023/day19_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,38 @@
[advent-of-code-2023.day19 :refer :all]
[advent-of-code-2023.test-utils :as tu]))

(defonce ^:private example-input (parse-input ""))
(defonce ^:private example-input (parse-input "px{a<2006:qkq,m>2090:A,rfg}
pv{a>1716:R,A}
lnx{m>1548:A,A}
rfg{s<537:gd,x>2440:R,A}
qs{s>3448:A,lnx}
qkq{x<1416:A,crn}
crn{x>2662:A,R}
in{s<1351:px,qqz}
qqz{s>2770:qs,m<1801:hdj,R}
gd{a>3333:R,R}
hdj{m>838:A,pv}
{x=787,m=2655,a=1222,s=2876}
{x=1679,m=44,a=2067,s=496}
{x=2036,m=264,a=79,s=2244}
{x=2461,m=1339,a=466,s=291}
{x=2127,m=1623,a=2188,s=1013}"))

(def ^:private input (parse-input (tu/slurp-input "resources/day19.txt")))

(deftest day19-1-example-test
(testing "day19-1 example"
(is (= nil
(day19-1 example-input)))))
(is (= 19114 (day19-1 example-input)))))

(deftest day19-1-test
(testing "day19-1"
(is (= nil
(day19-1 input)))))
(is (= 397134 (day19-1 input)))))

(deftest day19-2-example-test
(testing "day19-2 example"
(is (= nil
(day19-2 example-input)))))
(is (= 167409079868000 (day19-2 example-input)))))

(deftest day19-2-test
(testing "day19-2"
(is (= nil
(day19-2 input)))))
(is (= 127517902575337 (day19-2 input)))))

0 comments on commit f61fde7

Please sign in to comment.