From 7b0c6a854db41119207dc159a815cd22b5cef938 Mon Sep 17 00:00:00 2001 From: Nikita Hasert Date: Tue, 12 Dec 2023 22:22:46 +0100 Subject: [PATCH] Day 12: Solve part 1 and 2 --- src/advent_of_code_2023/day12.clj | 56 +++++++++++++++++++++++-- test/advent_of_code_2023/day12_test.clj | 19 +++++---- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/advent_of_code_2023/day12.clj b/src/advent_of_code_2023/day12.clj index 9cdf73c..1a3233f 100644 --- a/src/advent_of_code_2023/day12.clj +++ b/src/advent_of_code_2023/day12.clj @@ -1,9 +1,59 @@ (ns advent-of-code-2023.day12 (:require + [clojure.string :as string] [advent-of-code-2023.utils.string :as u])) -(defn parse-input [input]) +(defn parse-input [input] + (when (seq input) + (mapv (fn [line] + (let [[springs occ] (u/split-sections line #" ")] + {:springs springs + :occurrences (u/read-longs occ #",")})) + (u/split-sections input u/line-endings)))) -(defn day12-1 [parsed-input]) +(def count-possibilities + (memoize + (fn + ([{:keys [springs occurrences]}] + (count-possibilities springs occurrences 0)) + ([[s & sp :as springs] [^long o & ocs :as occurrences] ^long curr-match] + (cond + ;; We correctly guessed the springs + (and (empty? springs) (empty? occurrences)) 1 + (and (empty? springs) (= o curr-match)) (recur springs ocs 0) + ;; We made the wrong decision in the past + ;; and consumed the occurrences to quickly + (and (empty? occurrences) (seq (drop-while #{\. \?} springs))) 0 + ;; Skip across . when not in a match + (and (#{\.} s) (zero? curr-match)) + (count-possibilities sp occurrences 0) + ;; We matched springs correctly so far + (and (#{\.} s) (= curr-match o)) (count-possibilities sp ocs 0) + ;; Found a spring, begin the match + (and (#{\#} s) (zero? curr-match)) + (count-possibilities sp occurrences (inc curr-match)) + ;; Found a spring continue the match + (and (#{\#} s) (< curr-match o)) (recur sp occurrences (inc curr-match)) + ;; We can either match at this point or not + (and (#{\?} s) (zero? curr-match)) + (+ (count-possibilities (concat [\#] sp) occurrences curr-match) + (count-possibilities (concat [\.] sp) occurrences curr-match)) + ;; We have to finish the match here, we have no other choice + (and (#{\?} s) (= curr-match o)) (recur sp ocs 0) + ;; We have to continue the match here, we have no other choice + (and (#{\?} s) (< curr-match o)) (recur sp occurrences (inc curr-match)) + :else 0))))) -(defn day12-2 [parsed-input]) \ No newline at end of file +(defn day12-1 [spring-lines] + (transduce + (map count-possibilities) + + spring-lines)) + +(defn day12-2 [spring-lines] + (->> spring-lines + (mapv (fn [sl] + (-> sl + (update ,,, :occurrences #(apply concat (repeat 5 %))) + (update ,,, :springs #(string/join "?" (repeat 5 %)))))) + (pmap count-possibilities) + (reduce +))) \ No newline at end of file diff --git a/test/advent_of_code_2023/day12_test.clj b/test/advent_of_code_2023/day12_test.clj index 4797533..891ba9f 100644 --- a/test/advent_of_code_2023/day12_test.clj +++ b/test/advent_of_code_2023/day12_test.clj @@ -4,26 +4,27 @@ [advent-of-code-2023.day12 :refer :all] [advent-of-code-2023.test-utils :as tu])) -(defonce ^:private example-input (parse-input "")) +(defonce ^:private example-input (parse-input "???.### 1,1,3 +.??..??...?##. 1,1,3 +?#?#?#?#?#?#?#? 1,3,1,6 +????.#...#... 4,1,1 +????.######..#####. 1,6,5 +?###???????? 3,2,1")) (def ^:private input (parse-input (tu/slurp-input "resources/day12.txt"))) (deftest day12-1-example-test (testing "day12-1 example" - (is (= nil - (day12-1 example-input))))) + (is (= 21 (day12-1 example-input))))) (deftest day12-1-test (testing "day12-1" - (is (= nil - (day12-1 input))))) + (is (= 7084 (day12-1 input))))) (deftest day12-2-example-test (testing "day12-2 example" - (is (= nil - (day12-2 example-input))))) + (is (= 525152 (day12-2 example-input))))) (deftest day12-2-test (testing "day12-2" - (is (= nil - (day12-2 input))))) + (is (= 8414003326821 (day12-2 input)))))