Skip to content

Instantly share code, notes, and snippets.

@ghadishayban
Created December 3, 2023 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ghadishayban/c09b298235f73cb56e223f46c53873e5 to your computer and use it in GitHub Desktop.
Save ghadishayban/c09b298235f73cb56e223f46c53873e5 to your computer and use it in GitHub Desktop.
(ns day3
(:require [util]))
(defn adjacent-range
"returns [(dec lo), (inc hi)], lo clamped by 0, hi clamped by arg"
[lo hi hi-clamp]
[(max (dec lo) 0)
(min (inc hi) hi-clamp)])
(defn scan-adjacent
"Calls (f line adjacent-lines) for every line, concatenating results.
Every line has 3 adjacent lines, except for the first and last lines"
[f lines]
(->> (range (count lines))
(mapcat (fn [n]
(let [[lo hi] (adjacent-range n (inc n) (count lines))
adjacent (map lines (range lo hi))]
(f (lines n) adjacent))))))
(defn touching?
"given bounds (hi exclusive) returns predicate of match rets (from util/match)"
[lo hi]
(fn [{:keys [start end]}]
(and (> end lo) (< start hi))))
(defn extract-part-nums
"returns coll of integer parts"
[line adjacent]
(let [len (count line)
symbols (mapcat #(util/matches #"[^.0-9]" %) adjacent)]
(->> (util/matches #"\d+" line)
(keep (fn [{:keys [start end match]}]
(let [[lo hi] (adjacent-range start end len)]
(when (some (touching? lo hi) symbols)
(parse-long match))))))))
(defn extract-gears
"returns coll of gear maps with key :ratio"
[line adjacent]
(let [len (count line)
numbers (mapcat #(util/matches #"\d+" %) adjacent)]
(->> (util/matches #"\*" line) ;; collect candidate gears
(map (fn [{:keys [start end]}]
(let [[lo hi] (adjacent-range start end len)]
;; and the numbers that they touch
(filter (touching? lo hi) numbers))))
(filter #(= 2 (count %)))
(map (fn [nums]
{:ratio (apply * (map (comp parse-long :match) nums))})))))
(comment
;; part1
(apply + (scan-adjacent extract-part-nums (util/lines "day3.input")))
;; part2
(apply + (map :ratio (scan-adjacent extract-gears (util/lines "day3.input")))))
(ns util
(:require [clojure.java.io :as jio]))
(defn lines
[fname]
(with-open [r (jio/reader fname)]
(vec (line-seq r))))
(defn matches
"for every match in s, returns :start/:end indexes, end exclusive, and :match, the matching (sub)string"
[regex s]
(let [m (re-matcher regex s)]
(loop [acc []]
(if (.find m)
(recur (conj acc {:start (.start m)
:end (.end m)
:match (.group m)}))
acc))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment