Skip to content

Instantly share code, notes, and snippets.

@exupero
Last active December 25, 2018 20:09
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 exupero/454072fb8b4e5f0dadab28de2b95a7f4 to your computer and use it in GitHub Desktop.
Save exupero/454072fb8b4e5f0dadab28de2b95a7f4 to your computer and use it in GitHub Desktop.
Advent of Code 2018
(ns exupero.advent-of-code.2018
(:require [clojure.string :as string]
[clojure.set :refer [intersection rename-keys map-invert]]
[clojure.zip :as zip]
[net.cgrand.xforms :as xf]))
(def parse-int #(Integer/parseInt %))
; Day 1, puzzle 1
(def input-1 (map parse-int (string/split-lines (slurp "./resources/advent-of-code/2018/day-1-input.txt"))))
(reduce + input-1)
; Day 1, puzzle 2
(->> input-1 cycle (reductions +)
(reduce (fn [seen item]
(if (seen item)
(reduced item)
(conj seen item)))
#{}))
; Day 2, puzzle 1
(def input-2 (string/split-lines (slurp "./resources/advent-of-code/2018/day-2-input.txt")))
(sequence
(comp
(map frequencies)
(xf/by-key (comp (partial intersection #{2 3}) set vals) xf/count)
(xf/into {})
(map (fn [{twos #{2} threes #{3} both #{2 3}}]
(* (+ twos both) (+ threes both)))))
input-2)
; Day 2, puzzle 2
(sequence
(comp
(map (partial apply map vector))
(filter (comp #{1} count (partial filter (partial apply not=))))
(map (partial transduce
(comp
(filter (partial apply =))
(map first))
str)))
(for [a input-2, b input-2 :while (not= a b)]
[a b]))
; Day 3, puzzle 1
(def input-3
(map
(fn [s]
(let [[_ id x y w h] (re-matches #"#(\d+) @ (\d+),(\d+): (\d+)x(\d+)" s)]
{:id id
:x (parse-int x)
:y (parse-int y)
:width (parse-int w)
:height (parse-int h)}))
(string/split-lines (slurp "./resources/advent-of-code/2018/day-3-input.txt"))))
(sequence
(comp
(mapcat (fn [{:keys [x y width height]}]
(for [x' (range width), y' (range height)]
[(+ x x') (+ y y')])))
(xf/by-key identity xf/count)
(filter (comp #(< 1 %) second))
xf/count)
input-3)
; Day 3, puzzle 2
(defn intersects? [{x1 :x y1 :y w1 :width h1 :height}
{x2 :x y2 :y w2 :width h2 :height}]
(not (or (< (+ x1 w1) x2)
(< (+ y1 h1) y2)
(< (+ x2 w2) x1)
(< (+ y2 h2) y1))))
(sequence
(comp
(remove (fn [box]
(some #(and (not= (:id box) (:id %))
(intersects? box %))
input-3)))
(map :id))
input-3)
; Day 4, puzzle 1
(defn spillover [k f]
(fn [rf]
(let [value (volatile! nil)]
(fn
([] (rf))
([result] (rf result))
([result item]
(if-let [v (k item)]
(do (vreset! value v)
(rf result item))
(rf result (f item @value))))))))
(def input-4
(sequence
(comp
(map (fn [s]
(let [[_ year month day hour minute event guard-id]
(re-matches #"\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (Guard #(\d+) begins shift|wakes up|falls asleep)" s)]
{:year (parse-int year)
:month (parse-int month)
:day (parse-int day)
:hour (parse-int hour)
:minute (parse-int minute)
:event (cond
(re-find #"begins shift" event) :begins-shift
(= event "falls asleep") :falls-asleep
(= event "wakes up") :wakes-up)
:guard-id (when guard-id (parse-int guard-id))})))
(xf/sort-by (juxt :year :month :day :hour :minute))
(spillover :guard-id #(assoc %1 :guard-id %2)))
(string/split-lines (slurp "./resources/advent-of-code/2018/day-4-input.txt"))))
(defn spans [k v t]
(fn [rf]
(let [start (volatile! nil)]
(fn
([] (rf))
([result] (rf result))
([result item]
(condp = (t item)
:start (do (vreset! start (v item)) result)
:end (let [s @start]
(vreset! start nil)
(rf result
{:key (k item)
:start s
:end (v item)}))))))))
(def guard-minutes-asleep
(sequence
(comp
(remove (comp #{:begins-shift} :event))
(spans :guard-id :minute (comp {:falls-asleep :start, :wakes-up :end} :event))
(mapcat (fn [{k :key :keys [guard-id start end]}]
(for [m (range start end)]
{:guard-id k :minute m}))))
input-4))
(sequence
(comp
(xf/by-key :guard-id (comp
(xf/by-key :minute xf/count)
(xf/sort-by second >)
(xf/into [])))
(xf/sort-by #(reduce + (map second (second %))) >)
(map (fn [[id [[minute]]]]
(* id minute)))
(take 1))
guard-minutes-asleep)
; Day 4, puzzle 2
(sequence
(comp
(xf/by-key (juxt :guard-id :minute) xf/count)
(xf/sort-by second >)
(map first)
(map (partial apply *))
(take 1))
guard-minutes-asleep)
; Day 5, puzzle 1
(def input-5 (string/trim (slurp "./resources/advent-of-code/2018/day-5-input.txt")))
(defn reactive? [a b]
(and a b (not= a b)
(= (string/lower-case a) (string/lower-case b))))
(defn react [input]
(loop [loc (-> input vec zip/vector-zip zip/next)]
(if (zip/end? loc)
(zip/root loc)
(let [cur (zip/node loc)
left (some-> loc zip/left zip/node)
right (some-> loc zip/right zip/node)]
(cond
(reactive? left cur) (recur (-> loc zip/remove zip/remove))
(reactive? cur right) (recur (-> loc zip/right zip/remove zip/remove))
:else (recur (zip/next loc)))))))
(count (react input-5))
; Day 5, puzzle 2
(sequence
(comp
(distinct)
(map (fn [c]
(->> input-5
(remove #{(first (string/lower-case c))
(first (string/upper-case c))})
react
count)))
(xf/sort-by identity)
(take 1))
input-5)
; Day 6, puzzle 1
(def input-6 (map
(fn [s]
(let [[_ x y] (re-matches #"(\d+), (\d+)" s)]
(mapv parse-int [x y])))
(string/split-lines (slurp "./resources/advent-of-code/2018/day-6-input.txt"))))
(def extent (juxt (partial apply min) (partial apply max)))
(defn manhattan-distance [a b]
(reduce + (map (comp #(Math/abs %) -) a b)))
(defn boundary? [[x y] [min-x max-x] [min-y max-y]]
(or (<= x min-x)
(<= y min-y)
(>= x max-x)
(>= y max-y)))
(defn bests-by [f comp]
(let [best (volatile! [[] nil])]
(fn [rf]
(fn
([] (rf))
([result] (rf (rf result (first @best))))
([result item]
(let [[_ v] @best
k (f item)]
(cond
(= k v)
(do (vswap! best update 0 conj item)
result)
(or (nil? v) (comp k v))
(do (vreset! best [[item] k])
result))))))))
(defn largest-manhattan-area [coords]
(let [[min-x max-x] (extent (map first coords))
[min-y max-y] (extent (map second coords))]
(sequence
(comp
(map (fn [location]
{:location location
:closest-coords (sequence
(bests-by #(manhattan-distance location %) <)
coords)}))
(filter (comp #{1} count :closest-coords))
(xf/by-key (comp first :closest-coords) :location (xf/into []))
(remove (fn [[_ locations]]
(some #(boundary? % [min-x max-x] [min-y max-y])
locations)))
(map (comp count second))
(xf/sort-by identity >)
(take 1)
)
(for [x (range min-x (inc max-x))
y (range min-y (inc max-y))]
[x y]))))
(largest-manhattan-area input-6)
; Day 6, puzzle 2
(defn locations-within-total-distance [coords distance-cutoff]
(let [[min-x max-x] (extent (map first coords))
[min-y max-y] (extent (map second coords))]
(sequence
(comp
(map (fn [location]
(transduce
(map #(manhattan-distance location %))
+ coords)))
(filter #(< % distance-cutoff))
xf/count)
(for [x (range min-x (inc max-x))
y (range min-y (inc max-y))]
[x y]))))
(locations-within-total-distance input-6 10000)
; Day 7, puzzle 1
(def input-7 (map
(fn [s]
(let [[_ a b] (re-matches #"Step (.) must be finished before step (.) can begin." s)]
[a b]))
(string/split-lines (slurp "./resources/advent-of-code/2018/day-7-input.txt"))))
(defn dependencies [input]
(into (zipmap (distinct (mapcat seq input))
(repeat #{}))
(xf/by-key second first (xf/into #{}))
input))
(def no-dependencies
(comp
(filter (comp empty? val))
(map key)
(xf/sort-by name)))
(defn excise-dependency [dependency]
(comp
(remove (comp #{dependency} key))
(map #(update % 1 disj dependency))))
(defn topological-sort [graph]
(when-let [[step] (seq (sequence no-dependencies graph))]
(concat [step]
(topological-sort
(into {} (excise-dependency step) graph)))))
(apply str (topological-sort (dependencies input-7)))
; Day 7, puzzle 2
(defn gantt-time [graph time-to-do workers]
(loop [t 0
graph graph
workers (repeat workers nil)]
(let [[step] (sequence
(comp
no-dependencies
(remove (set (map first workers))))
graph)]
(cond
(empty? graph)
t
(and step (some nil? workers))
(recur t
graph
(assoc (vec workers)
(.indexOf workers nil)
[step (+ t (time-to-do step))]))
:else
(let [[s t'] (apply min-key second (remove nil? workers))]
(recur t'
(into {} (excise-dependency s) graph)
(map (fn [[_ done :as worker]]
(when-not (= t' done)
worker))
workers)))))))
(gantt-time
(dependencies input-7)
(into {} (map vector (map str "ABCDEFGHIJKLMNOPQRSTUVWXYZ") (iterate inc 61)))
5)
; Day 8, puzzle 1
(def input-8 (-> (slurp "./resources/advent-of-code/2018/day-8-input.txt")
string/trim
(string/split #" ")
(->> (map parse-int))))
(defn parse-tree
([values] (ffirst (parse-tree values 1)))
([values n]
(loop [n n
values values
nodes []]
(if (pos? n)
(let [[node-count metadata-count & values] values
[children values] (parse-tree values node-count)
[metadata values] (split-at metadata-count values)]
(recur (dec n)
values
(conj nodes {:children children :metadata metadata})))
[nodes values]))))
(->> (parse-tree input-8)
(tree-seq map? :children)
(mapcat :metadata)
(reduce +))
; Day 8, puzzle 2
(defn node-value [{:keys [children metadata]}]
(if (seq children)
(->> metadata
(map (fn [i]
(node-value (get children (dec i) {}))))
(reduce +))
(reduce + metadata)))
(node-value (parse-tree input-8))
; Day 9, puzzle 1
(def input-9 (let [s (string/trim (slurp "./resources/advent-of-code/2018/day-9-input.txt"))
[_ players marbles] (re-matches #"(\d+) players; last marble is worth (\d+) points" s)]
{:players (parse-int players)
:highest-marble (parse-int marbles)}))
(defn zip-right-wrap [loc]
(or (zip/right loc) (zip/leftmost loc)))
(defn zip-left-wrap [loc]
(or (zip/left loc) (zip/rightmost loc)))
(defn place-marble [marbles marble]
(-> marbles zip-right-wrap (zip/insert-right marble) zip/right))
(defn remove-scoring-marble [marbles]
(let [marbles (nth (iterate zip-left-wrap marbles) 7)]
[(zip/node marbles)
(-> marbles zip/remove zip-right-wrap)]))
(defn top-marble-score [players highest-marble]
(loop [marbles (zip/down (zip/vector-zip [0]))
scores {}
players (cycle (range 1 (inc players)))
marble 1]
(cond
(< highest-marble marble) (apply max-key val scores)
(zero? (mod marble 23)) (let [[scoring-marble marbles] (remove-scoring-marble marbles)]
(recur marbles
(update scores (first players) (fnil + 0) marble scoring-marble)
(next players)
(inc marble)))
:else (recur (place-marble marbles marble)
scores
(next players)
(inc marble)))))
(second (top-marble-score (input-9 :players) (input-9 :highest-marble)))
; Day 9, puzzle 2
(second (top-marble-score (input-9 :players) (* 100 (input-9 :highest-marble))))
; Day 10, puzzle 1
(defn parse-input-10 [line]
(let [[_ x y dx dy] (re-matches #"position=<\s*(-?\d+),\s*(-?\d+)> velocity=<\s*(-?\d+),\s*(-?\d+)>" line)]
{:position [(parse-int x) (parse-int y)]
:velocity [(parse-int dx) (parse-int dy)]}))
(def input-10 (map parse-input-10 (string/split-lines (slurp "./resources/advent-of-code/2018/day-10-input.txt"))))
(defn advance-light [n {:keys [velocity] :as point}]
(update point :position (partial mapv #(+ %1 (* n %2))) velocity))
(defn drawable? [coords]
(let [[top bottom] (extent (map second coords))]
(> 80 (- bottom top))))
(defn draw-lights [coords]
(let [[left right] (extent (map first coords))
[top bottom] (extent (map second coords))]
(transduce
(comp
(map string/join)
(interpose "\n"))
str
(for [y (range top (inc bottom))]
(for [x (range left (inc right))]
(if (contains? coords [x y]) \# \space))))))
(def pattern
(ffirst
(sequence
(comp
(map (partial map :position))
(map set)
(drop-while (complement drawable?))
(take-while drawable?)
(bests-by height <))
(iterate #(map (partial advance-light 1) %) input-10))))
(println (draw-lights pattern))
; Day 10, puzzle 2
(sequence
(comp
(map (partial map :position))
(map set)
(take-while (partial not= pattern))
xf/count)
(iterate #(map (partial advance-light 1) %) input-10))
; Day 11, puzzle 1
(def input-11 (parse-int (string/trim (slurp "./resources/advent-of-code/2018/day-11-input.txt"))))
(defn cell-power [grid-serial-number x y]
(let [rack-id (+ x 10)]
(-> (* y rack-id)
(+ grid-serial-number)
(* rack-id)
(as-> $ (mod (int (/ $ 100)) 10))
(- 5))))
(defn block-power [grid-serial-number size x y]
(reduce + (for [dx (range size), dy (range size)]
(cell-power grid-serial-number (+ x dx) (+ y dy)))))
(let [grid-serial-number input-11]
(sequence
(comp
(bests-by #(apply block-power grid-serial-number 3 %) >)
(map first))
(for [x (range 1 299), y (range 1 299)]
[x y])))
; Day 11, puzzle 2
(defn summed-area-table [f table [x y]]
(assoc table [x y]
(+ (f x y)
(table [(dec x) y] 0)
(table [x (dec y)] 0)
(- (table [(dec x) (dec y)] 0)))))
(defn area [summed-area-table [x y size]]
(let [x (dec x), y (dec y)]
(+ (summed-area-table [(+ x size) (+ y size)])
(- (summed-area-table [(+ x size) y] 0))
(- (summed-area-table [x (+ y size)] 0))
(summed-area-table [x y] 0))))
(let [cells (for [x (range 1 301), y (range 1 301)] [x y])
table (reduce (partial summed-area-table #(cell-power input-11 %1 %2)) {} cells)]
(sequence
(bests-by (partial area table) >)
(for [[x y] cells, size (range 1 (- 300 (max x y)))]
[x y size])))
; Day 12, puzzle 1
(defn parse-input-12 [s]
(let [[initial _ & rules] (string/split-lines s)
[_ initial] (string/split initial #": ")
plant? #(= \# %)]
{:initial (into {} (map #(do [%1 (plant? %2)]) (range) initial))
:rules (into {}
(map (fn [s]
(let [[_ input output] (re-matches #"([.#]{5}) => ([.#])" s)]
[(mapv plant? input) (plant? (first output))])))
rules)}))
(def input-12 (parse-input-12 (slurp "./resources/advent-of-code/2018/day-12-input.txt")))
(defn advance-plants [rules plants]
(let [[low high] (extent (map key (filter val plants)))]
(into {}
(map (fn [i]
(let [s (mapv #(plants % false)
(range (- i 2) (+ i 3)))]
[i (rules s false)])))
(range (- low 2) (+ high 3)))))
(defn generations [{:keys [initial rules]}]
(map #(reduce + (map first (filter val %)))
(iterate (partial advance-plants rules) initial)))
(sequence
(comp
(drop 20)
(take 1))
(generations input-12))
; Day 12, puzzle 2
(let [sample 1000
target 50e9
[[x dx]] (sequence
(comp
(xf/partition 2 1 (xf/into []))
(map (fn [[a b]] [b (- b a)]))
(take sample)
xf/last)
(generations input-12))]
(java.math.BigDecimal. (+ x (* dx (- target sample)))))
; Day 13, puzzle 1
(def input-13 (slurp "./resources/advent-of-code/2018/day-13-input.txt"))
(def e [1 0])
(def w [-1 0])
(def n [0 -1])
(def s [0 1])
(def left [0 -1])
(def right [0 1])
(def straight [1 0])
(def next-turn {left straight, straight right, right left})
(defn ** [[r1 i1] [r2 i2]]
[(+ (* r1 r2) (- (* i1 i2)))
(+ (* r1 i2) (* r2 i1))])
(defn parse-grid [input]
(into {}
(comp
(map-indexed (fn [row line]
(map-indexed
#(do [[%1 row] %2])
line)))
(mapcat seq))
(string/split-lines input)))
(defn parse-track [input]
(let [grid (parse-grid input)]
{:track (into {} (remove (comp #{\space \< \> \v \^ \- \|} val)) grid)
:carts (into {}
(comp
(filter (comp #{\< \> \^ \v} val))
(map (fn [[location c]]
{:location location
:direction (get {\< [-1 0], \> [1 0], \^ [0 -1], \v [0 1]} c)
:next-turn left}))
(map (juxt :location identity)))
grid)}))
(defn advance-cart [track {[x y :as location] :location turn :next-turn :keys [direction] :as cart}]
(let [new-location (mapv + location direction)
cart (assoc cart :location new-location)
new-track (track new-location)]
(cond
(nil? new-track) cart
(= \+ new-track) (assoc cart :direction (** direction turn), :next-turn (next-turn turn))
(and (= \\ new-track) (#{n s} direction)) (update cart :direction ** left)
(and (= \\ new-track) (#{e w} direction)) (update cart :direction ** right)
(and (= \/ new-track) (#{n s} direction)) (update cart :direction ** right)
(and (= \/ new-track) (#{e w} direction)) (update cart :direction ** left))))
(def grid-order (comp vec reverse))
(defn advance-carts-until-collision [track carts]
(let [carts (reduce
(fn [carts cart]
(let [cart' (advance-cart track cart)]
(if (carts (cart' :location))
(reduced {:collision cart'})
(-> carts
(dissoc (cart :location))
(assoc (cart' :location) cart')))))
carts (sort-by (comp grid-order :location) (vals carts)))]
(if-let [collision (:collision carts)]
(reduced collision)
carts)))
(defn carts [advance-carts input]
(let [{:keys [track carts]} (parse-track input)]
(iterate (partial advance-carts track) carts)))
(sequence
(comp
(filter reduced?)
(map deref)
(map :location)
(take 1))
(carts advance-carts-until-collision input-13))
; Day 13, puzzle 2
(defn advance-carts-removing-collisions [track carts]
(reduce
(fn [carts cart]
(if (carts (cart :location))
(let [cart' (advance-cart track cart)]
(if (carts (cart' :location))
(dissoc carts (cart :location) (cart' :location))
(-> carts
(dissoc (cart :location))
(assoc (cart' :location) cart'))))
carts))
carts (sort-by (comp grid-order :location) (vals carts))))
(sequence
(comp
(drop-while (comp (partial < 1) count))
(take 1)
(map keys))
(carts advance-carts-removing-collisions input-13))
; Day 14, puzzle 1
(def input-14 (string/trim (slurp "./resources/advent-of-code/2018/day-14-input.txt")))
(def divmod (juxt (comp int /) mod))
(defn next-recipes [[indices recipies]]
(let [total (transduce (map recipies) + indices)
recipies (if (<= 10 total)
(into recipies (divmod total 10))
(conj recipies total))
c (count recipies)]
[(map #(mod (+ 1 % (recipies %)) c) indices)
recipies]))
(defn eventual-recipies [to-take next-n [initial-indices initial-recipies]]
(sequence
(comp
(drop to-take) ; more than necessary, but faster than checking each iteration
(take 1)
(map (comp #(subvec % to-take (+ to-take next-n)) second)))
(iterate next-recipes [initial-indices initial-recipies])))
(->> [[0 1] [3 7]]
(eventual-recipies (parse-int input-14) 10)
first
(apply str)
time)
; Day 14, puzzle 2
(-> (iterate next-recipes [[0 1] [3 7]])
(nth 20e6)
second
(->> (apply str))
(.indexOf input-14))
; Day 16, puzzle 1
(defn parse-input-16 [s]
(let [[a b] (string/split s #"\n\n\n\n")]
{:examples (map
(fn [s]
(let [[before operation after] (string/split-lines s)
[_ before-registers] (re-matches #"Before: \[(.*)\]" before)
[_ after-registers] (re-matches #"After: \[(.*)\]" after)]
{:operation (map parse-int (re-seq #"\d+" operation))
:before (mapv parse-int (string/split before-registers #", "))
:after (mapv parse-int (string/split after-registers #", "))}))
(string/split a #"\n\n"))
:program (map
(fn [s]
(map parse-int (re-seq #"\d+" s)))
(string/split-lines b))}))
(def input-16 (parse-input-16 (slurp "./resources/advent-of-code/2018/day-16-input.txt")))
(defn op [f]
(fn [registers [_ a b c]]
(assoc registers c (f registers a b))))
(def ops
{:addr (op (fn [r a b] (+ (r a) (r b))))
:addi (op (fn [r a b] (+ (r a) b)))
:mulr (op (fn [r a b] (* (r a) (r b))))
:muli (op (fn [r a b] (* (r a) b)))
:banr (op (fn [r a b] (bit-and (r a) (r b))))
:bani (op (fn [r a b] (bit-and (r a) b)))
:borr (op (fn [r a b] (bit-or (r a) (r b))))
:bori (op (fn [r a b] (bit-or (r a) b)))
:setr (op (fn [r a _] (r a)))
:seti (op (fn [r a _] a))
:gtir (op (fn [r a b] (if (> a (r b)) 1 0)))
:gtri (op (fn [r a b] (if (> (r a) b) 1 0)))
:gtrr (op (fn [r a b] (if (> (r a) (r b)) 1 0)))
:eqir (op (fn [r a b] (if (= a (r b)) 1 0)))
:eqri (op (fn [r a b] (if (= (r a) b) 1 0)))
:eqrr (op (fn [r a b] (if (= (r a) (r b)) 1 0)))})
(defn valid-operations [{:keys [operation before after]}]
(filter
(comp #{after} #(% before operation) second)
ops))
(sequence
(comp
(filter (comp (partial <= 3) count valid-operations))
xf/count)
(input-16 :examples))
; Day 16, puzzle 2
(defn deduce-ops [examples]
(reduce
(fn [op->n example]
(let [valid-ops (sequence
(comp
(map key)
(remove op->n))
(valid-operations example))]
(if (= 1 (count valid-ops))
(assoc op->n (first valid-ops) (-> example :operation first))
op->n)))
{}
examples))
(let [{:keys [examples program]} input-16
n->op (map-invert (deduce-ops examples))]
(reduce
(fn [registers [n :as operation]]
(let [f (ops (n->op n))]
(f registers operation)))
[0 0 0 0]
program))
; Day 18, puzzle 1
(def input-18 (parse-grid (slurp "./resources/advent-of-code/2018/day-18-input.txt")))
(defn next-forest [cells]
(into {}
(map (fn [[location c]]
[location
(let [neighbors (frequencies (for [dx [-1 0 1]
dy [-1 0 1]
:when (not= [0 0] [dx dy])]
(cells (mapv + location [dx dy]))))]
(cond
(and (= c \.) (<= 3 (neighbors \| 0))) \|
(and (= c \|) (<= 3 (neighbors \# 0))) \#
(and (= c \#) (<= 1 (neighbors \# 0)) (<= 1 (neighbors \| 0))) \#
(= c \#) \.
:else c))]))
cells))
(defn resource-value [forest]
(let [summary (frequencies (vals forest))]
(* (summary \|) (summary \#))))
(resource-value (nth (iterate next-forest input-18) 10))
; Day 18, puzzle 2
(defn take-until-repeat [rf]
(let [seen (volatile! #{})]
(fn
([] (rf))
([result] (rf result))
([result item]
(if (@seen item)
(reduced result)
(do (vswap! seen conj item)
(rf result item)))))))
(defn predict-from-eventual-cycle [n xs]
(let [c (count xs)]
(if (< n c)
(nth xs n)
(let [repeats (->> xs reverse (sequence take-until-repeat) reverse)]
(nth repeats (mod (- n c) (count repeats)))))))
(predict-from-eventual-cycle
1000000000
(sequence
(comp
(map resource-value)
(take 1000))
(iterate next-forest input-18)))
; Day 20, puzzle 1
(def input-20 (string/trim (slurp "./resources/advent-of-code/2018/day-20-input.txt")))
(defn construct-map [directions]
(let [set-conj (fnil conj #{})]
(:doors
(reduce
(fn [{:keys [doors room checkpoints] :as walk} c]
(let [add-room (fn [direction]
(let [room' (mapv + room direction)]
(-> walk
(update-in [:doors room] set-conj room')
(update-in [:doors room'] set-conj room)
(assoc :room room'))))]
(condp = c
\^ walk
\$ walk
\E (add-room e)
\N (add-room n)
\W (add-room w)
\S (add-room s)
\( (update walk :checkpoints conj room)
\) (update walk :checkpoints pop)
\| (assoc walk :room (peek checkpoints)))))
{:doors {} :room [0 0] :checkpoints []}
directions))))
(defn maze-walk [doors location]
(loop [new-locations [[location 0]]
walk {location 0}]
(if (seq new-locations)
(let [new-locations (into {}
(comp
(map #(update % 1 inc))
(mapcat (fn [[location steps]]
(map #(do [% steps]) (doors location))))
(remove (comp walk first)))
new-locations)]
(recur new-locations (merge-with min walk new-locations)))
walk)))
(apply max (vals (maze-walk (construct-map input-20) [0 0])))
; Day 20, puzzle 2
(->> (maze-walk (construct-map input-20) [0 0])
vals
(filter (partial <= 1000))
count)
; Day 23, puzzle 1
(defn parse-day-23 [s]
(when-let [[_ x y z r] (re-matches #"pos=<(-?\d+),(-?\d+),(-?\d+)>, r=(\d+)" s)]
{:position (mapv parse-int [x y z])
:radius (parse-int r)}))
(def input-23 (map parse-day-23 (string/split-lines (slurp "./resources/advent-of-code/2018/day-23-input.txt"))))
(let [bots input-23
[{:keys [position radius]}] (sort-by :radius > bots)]
(sequence
(comp
(map (comp (partial manhattan-distance position) :position))
(filter (partial >= radius))
xf/count)
bots))
; Day 25, puzzle 1
(defn parse-input-25 [s]
(mapv parse-int (re-seq #"-?\d+" s)))
(def input-25 (map parse-input-25 (string/split-lines (slurp "./resources/advent-of-code/2018/day-25-input.txt"))))
(defn constellations [pts]
(let [connected? (fn [pts pt]
(some #(>= 3 (manhattan-distance % pt)) pts))]
(reduce
(fn [cs pt]
(let [{connected true not-connected false} (group-by (comp boolean #(connected? % pt)) cs)]
(if (seq connected)
(conj not-connected (into #{pt} (mapcat seq) connected))
(conj cs #{pt}))))
() pts)))
(count (constellations input-25))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment