Skip to content

Commit

Permalink
day 4
Browse files Browse the repository at this point in the history
  • Loading branch information
narimiran committed Dec 4, 2024
1 parent dfafa7b commit 083e71d
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 2 deletions.
162 changes: 162 additions & 0 deletions clojure/day04.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
^{:nextjournal.clerk/visibility {:code :hide :result :hide}}
(ns day04
{:nextjournal.clerk/auto-expand-results? true
:nextjournal.clerk/toc :collapsed}
(:require aoc))


;; # Day 4: Ceres Search
;;
;; We're not on Earth any more!
;; Now we're on the Ceres monitoring station and it xmas-time.
;;
;; An Elf wants us to help with her word search, so let's do that.
;; (The search for Chief Historian can wait a bit, I guess.)





;; ## Input parsing
;;
;; We are given a word search that looks like this:
(def example "MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX")

;; We need to find how many times the word `XMAS` appears there, and we need
;; to search in 8 directions.
;;
;; Since this will involve searching in a 2D grid, I have a helper in my
;; [aoc module](./aoc) which converts a list into a hashmap, where keys are
;; the coordinates and values are characters at those positions:
(defn parse-data [data]
(-> data
aoc/parse-lines
aoc/grid->point-map))

;; Now we can convert our inputs to these hashmaps:
;;
(def example-grid (parse-data example))
(def grid (parse-data (aoc/read-input 4)))





;; ## Part 1
;;
;; We will go through all positions in our input and check if, starting from
;; there, we can find the word `XMAS` in any of 8 directions.\
;; This we can do with a Cartesian product between three `dx` possibilities
;; and three `dy` possibilities.
;; (This also gives us 9th "direction", when both deltas are zero, which will
;; never match the word we're looking for, so we're just leave it in.)
;;
;; Once again, I'm using one of my helpers.
;; This time it is `do-count`, which is a simple macro allowing me to write
;; an equivalent of `(count (for [... ...] 1))`, without unnecessary creating
;; a list of ones, just to count the number of them.\
;; Anything you can write in a `seq-exprs` (the stuff inside of `[ ... ]`)
;; of a [`for`](https://clojuredocs.org/clojure.core/for) or a
;; [`do-seq`](https://clojuredocs.org/clojure.core/doseq) (see some examples
;; on those links), you can also write here: for example, use `:when`:
;;
(defn part-1 [grid]
(let [letters (map-indexed vector "XMAS")]
(aoc/do-count
[[[x y] c] grid
:when (= \X c)
dx [-1 0 1]
dy [-1 0 1]
:when (every? (fn [[i l]]
(= l (grid [(+ x (* i dx))
(+ y (* i dy))])))
letters)])))

;; If the position we're at isn't a letter `X`, we won't even bother to
;; check its neighbours: if the first `:when` is false,
;; the inner loops are skipped.\
;; Otherwise, we check all the directions for a potential `XMAS`.
;; Using the [`every?` function](https://clojuredocs.org/clojure.core/every_q)
;; means we will short-circuit on the first letter that doesn't satisfy the predicate.
;;
(part-1 example-grid)
(part-1 grid)






;; ## Part 2
;;
;; > The Elf looks quizzically at you. Did you misunderstand the assignment?
;;
;; Well, my dear Elf, to be honest, I initially misunderstood the first part too!
;; I didn't read the task description carefully and I was searching only in
;; four directions.
;; But ok, nobody will know about that.
;;
;; > this isn't actually an `XMAS` puzzle; it's an `X-MAS` puzzle
;;
;; There are four ways to have X-MAS:
;; ```
;; M.S M.M S.S S.M
;; .A. .A. .A. .A.
;; M.S S.S M.M S.M
;; ```
;;
;; As we can see, each diagonal will contain either `MAS` or `SAM`.\
;; We will check all points to see if their diagonals satisfy this condition:
;;
(defn part-2 [grid]
(let [diags #{(vec "MAS") (vec "SAM")}
deltas [-1 0 1]]
(aoc/do-count
[[x y] (keys grid)
:when (and (diags (for [d deltas]
(grid [(+ x d) (+ y d)])))
(diags (for [d deltas]
(grid [(- x d) (+ y d)]))))])))

;; The only difference between two diagonals is if the deltas for `x` and `y`
;; have the same or the opposite sign. (Notice the `(- x d)` in the second one.)
;;
(part-2 example-grid)
(part-2 grid)






;; ## Conclusion
;;
;; Today no visualizations, sorry.\
;; Hopefully, it's an exception and it doesn't mean that from now on
;; the visualizations are... wait for it... _no más_.
;;
;; Today's highlights:
;; - `aoc/grid->point-map`: convert a 2D list into a hashmap
;; - `:when`: write conditions inside of `for`/`doseq`
;; - `every?`: check if all elements of a collection satisfy a predicate







^{:nextjournal.clerk/visibility {:code :hide :result :hide}}
(defn -main [input]
(let [grid (parse-data input)]
[(part-1 grid)
(part-2 grid)]))
3 changes: 2 additions & 1 deletion clojure/tests/solutions_tests.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns solutions-tests
(:require
day01 day02 day03 ;day04 day05
day01 day02 day03 day04 ;day05
;; day06 day07 day08 day09 day10
;; day11 day12 day13 day14 day15
;; day16 day17 day18 day19 day20
Expand All @@ -26,6 +26,7 @@
(check-day 1 [11 31] [1222801 22545250])
(check-day 2 [2 4] [334 400])
(check-day 3 [161 48] [167090022 89823704])
(check-day 4 [18 9] [2534 1866])


(let [summary (run-tests)]
Expand Down
3 changes: 2 additions & 1 deletion index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ Task | Notebook | Comment
--- | --- | ---
[Day 1: Historian Hysteria](https://adventofcode.com/2024/day/1) | [day01.clj](clojure/day01) | Much easier than Day 1 2023. I like it!
[Day 2: Red-Nosed Reports](https://adventofcode.com/2024/day/2) | [day02.clj](clojure/day02) | The Problem Dampener would be useful for AoC!
[Day 3: Mull It Over](https://adventofcode.com/2024/day/2) | [day03.clj](clojure/day03) | Regex and chill.
[Day 3: Mull It Over](https://adventofcode.com/2024/day/3) | [day03.clj](clojure/day03) | Regex and chill.
[Day 4: Ceres Search](https://adventofcode.com/2024/day/4) | [day04.clj](clojure/day04) | No Más!

Loading

0 comments on commit 083e71d

Please sign in to comment.