Skip to content

Instantly share code, notes, and snippets.

@corasaurus-hex
Last active December 13, 2023 04:32
Show Gist options
  • Save corasaurus-hex/9cbe6a0190f1dce0acbe79ccfdcc9593 to your computer and use it in GitHub Desktop.
Save corasaurus-hex/9cbe6a0190f1dce0acbe79ccfdcc9593 to your computer and use it in GitHub Desktop.
(ns user
(:require [clojure.string :as str]
[hyperfiddle.rcf :refer [tests]]))
(hyperfiddle.rcf/enable!)
(defn window-for-index
[index rows]
(cond
(= 0 index)
[0 (vec (take 2 rows))]
(= (-> rows count dec) index)
[1 (vec (take-last 2 rows))]
(and (>= index 0) (<= index (-> rows count dec)))
[1 (->> rows (take (+ 2 index)) (take-last 3) vec)]
:else
nil))
(tests
(window-for-index 0 [:a :b :c :d :e]) := [0 [:a :b]]
(window-for-index 1 [:a :b :c :d :e]) := [1 [:a :b :c]]
(window-for-index 2 [:a :b :c :d :e]) := [1 [:b :c :d]]
(window-for-index 3 [:a :b :c :d :e]) := [1 [:c :d :e]]
(window-for-index 4 [:a :b :c :d :e]) := [1 [:d :e]]
(window-for-index 5 [:a :b :c :d :e]) := nil
(window-for-index -1 [:a :b :c :d :e]) := nil
)
(defn parse-number-ranges
[row]
(let [matcher (.matcher (re-pattern "(\\d+)") row)]
(loop [ranges []]
(if (.find matcher)
(recur (conj ranges [(.start matcher) (.end matcher)]))
ranges))))
(tests
(parse-number-ranges "467..114..") := [[0 3] [5 8]]
(subs "467..114.." 0 3) := "467"
(subs "467..114.." 5 8) := "114"
(parse-number-ranges "..*.467..114") := [[4 7] [9 12]]
(subs "..*.467..114" 4 7) := "467"
(subs "..*.467..114" 9 12) := "114"
)
(defn indexes-around-number-range
[window cursor-index number-range]
(let [[from to] number-range
max-index (count (get window cursor-index))
border-range (range (max 0 (dec from)) (min max-index (inc to)))]
(cond-> []
(> from 0)
(conj [cursor-index (dec from)])
(< to max-index)
(conj [cursor-index to])
(get window (dec cursor-index))
(into (map #(do [(dec cursor-index) %]) border-range))
(get window (inc cursor-index))
(into (map #(do [(inc cursor-index) %]) border-range)))))
(tests
(indexes-around-number-range ["...*......"
"..35..633."
"......#..."]
1
[2 4]) := [[1 1]
[1 4]
[0 1]
[0 2]
[0 3]
[0 4]
[2 1]
[2 2]
[2 3]
[2 4]])
(defn adjacent-characters
[window cursor-index number-range]
(map (comp str #(get-in window %))
(indexes-around-number-range window
cursor-index
number-range)))
(tests
(adjacent-characters ["-*&!+..58."
"%617@....."
"^)($#..58."]
1
[1 4]) := ["%" "@" "-" "*" "&" "!" "+" "^" ")" "(" "$" "#"]
(adjacent-characters ["617*......"
"-*&!.+.58."]
0
[0 3]) := ["*" "-" "*" "&" "!"]
(adjacent-characters [".+.58.-*&!"
"......*617"]
1
[7 10]) := ["*" "-" "*" "&" "!"]
(adjacent-characters [".*!*$....."
".%35#.633."
".&^-_.#..."]
1
[2 4]) := ["%" "#" "*" "!" "*" "$" "&" "^" "-" "_"]
)
(def non-symbol-characters? #{"0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "."})
(defn symbol-character?
[s]
(not (non-symbol-characters? s)))
(defn adjacent-to-symbol?
[window cursor-index number-range]
(boolean (some symbol-character? (adjacent-characters window cursor-index number-range))))
(tests
(adjacent-to-symbol? ["...*......"
"..35..633."
"......#..."] 1 [2 4]) := true
(adjacent-to-symbol? ["....*....."
"..35..633."
"......#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".........."
"..35*.633."
"......#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".........."
"..35..633."
"....*.#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".........."
"..35..633."
".*....#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".........."
".*35..633."
"......#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".*........"
"..35..633."
"......#..."] 1 [2 4]) := true
(adjacent-to-symbol? [".........."
"..35..633."
"......#..."] 1 [2 4]) := false
)
(defn parse-number
[window cursor-index number-range]
(parse-long (apply subs (get window cursor-index) number-range)))
(tests
(parse-number [".........."
"..35..633."
"......#..."] 1 [2 4]) := 35
)
(defn parse-input
[input-text]
(let [rows (str/split input-text #"\n")]
(loop [index 0
total 0]
(if (get rows index)
(let [[cursor-index window] (window-for-index index rows)
ranges (parse-number-ranges (get window cursor-index))
numbers-with-adjacent-symbols (->> ranges
(filter #(adjacent-to-symbol? window cursor-index %))
(map #(parse-number window cursor-index %)))]
(recur (inc index) (reduce + total numbers-with-adjacent-symbols)))
total))))
(tests
(let [input-text (str/join
"\n"
["467..114.."
"...*......"
"..35..633."
"......#..."
"617*......"
".....+.58."
"..592....."
"......755."
"...$.*...."
".664.598.."])
output-value 4361]
(parse-input input-text) := output-value)
)
(comment
(parse-input
(slurp "input")))
{:deps {com.hyperfiddle/rcf {:mvn/version "20220926-202227"}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment