adventofcode

Aleks 2021-12-09T04:44:08.450400Z

๐ŸงตDay 9 answers thread: post your answers here

mchampine 2021-12-09T05:45:56.451300Z

Part 1 quick and hacky but it works:

;; part 1
(def input
  (->> (util/load-lines "resources/day09.data")
       (util/split-lines-re #"")
       (mapv util/parse-ints)
       (map vec)
       (into [])))

(defn addpairs [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)])
(def surround [[1 0] [0 1] [-1 0] [0 -1]])
(defn neighbors [posn] (map addpairs (repeat posn) surround))

(defn adjs [brd pt]
  (remove nil? (map (partial util/getxy brd) (neighbors pt))))

(defn islowest? [brd pt]
  (< (util/getxy brd pt) (first (sort (adjs brd pt)))))

(defn low-points [brd]
  (for [x (range (count (first brd)))
        y (range (count brd))
        :when (islowest? brd [x y])] (util/getxy brd [x y])))

(reduce + (map inc (low-points input)))
;; => 530
;; part 2

(defn neighbors-on-board [brd pt]
  (filter #(util/getxy brd %) (neighbors pt)))

(defn step [brd acc-basin]
  (let [bn (map (partial neighbors-on-board brd) acc-basin)
        dac (distinct (apply concat bn))
        nn (filter #(not= 9 (util/getxy brd %)) dac)]
    (into acc-basin (set nn))))

(defn basin-size-at [brd pt]
  (count (util/fixed-point (partial step brd) (set [pt]))))

(->> (map (partial basin-size-at input) (low-ptsxy input))
     sort
     reverse
     (take 3)
     (reduce *))
;; => 1019494

2021-12-09T07:05:29.454Z

Simple solution, nothing special ... didn't even use frequencies.

(ns aoc-2021.day-9
  (:require [ :as io]
            [clojure.string :as str]
            [aoc.util :as util :refer [comp->]]))

(def input
  (->> (io/resource "2021/day9.txt")
       slurp
       str/split-lines
       (mapv (fn [line]
               (mapv (comp-> str parse-long) line)))))

;; Part 1
(defn adjacents [[y x]]
  [[y (dec x)]
   [y (inc x)]
   [(dec y) x]
   [(inc y) x]])

(->> (for [[y row] (util/seq-indexed input)
           [x n] (util/seq-indexed row)
           :let [min-adj (->> (adjacents [y x])
                              (keep (fn [position]
                                      (get-in input position)))
                              (reduce min))]
           :when (< n min-adj)]
       (inc n))
     (reduce +))
;=> 631


;; Part 2
(->> (for [[y row] (util/seq-indexed input)
           [x n] (util/seq-indexed row)
           :let [min-adj (->> (adjacents [y x])
                              (keep (fn [position]
                                      (get-in input position)))
                              (reduce min))]
           :when (< n min-adj)]
       (loop [basin #{}
              edges #{[y x]}]
         (if (seq edges)
           (let [new-edges (into #{}
                                 (comp (mapcat adjacents)
                                       (remove (fn [pos]
                                                 (= (get-in input pos 9) 9)))
                                       (remove basin))
                                 edges)]
             (recur (into basin new-edges)
                    new-edges))
           (count basin))))
     (sort-by identity >)
     (take 3)
     (apply *))
; => 821560

Aleks 2021-12-09T07:09:31.454300Z

> didnโ€™t even useย `frequencies`

๐Ÿ˜ 4
๐Ÿ˜… 5
Felipe 2021-12-11T17:43:37.055200Z

super mutable flood fill https://github.com/FelipeCortez/advent-of-code/blob/master/2021/09.clj

Benjamin 2021-12-11T18:41:49.056500Z

https://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day9.clj man your solutions are so simple. Learning a lot

genmeblog 2021-12-09T08:48:27.455400Z

lava!

๐Ÿ‘ 3
๐ŸŒ‹ 4
nbardiuk 2021-12-09T08:55:07.455800Z

smoke settles down

๐Ÿ‘ 2
Callum Oakley 2021-12-09T09:19:14.457600Z

not much to say about today. but I did use frequencies ๐Ÿ˜… actually I did think of something. Iโ€™m technically doing some unnecessary work tracing from every point all the way to itโ€™s corresponding low point, so tried wrapping basin in memoizeโ€ฆ which made it actually slower. I suppose the savings donโ€™t offset the overhead of the map lookups. nonsense, I wasnโ€™t memoizing properly 31ms/91ms https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/09.clj

Kirill Chernyshov 2021-12-09T09:23:45.458500Z

booooring day, couldn't find how to use frequencies (

๐Ÿ˜‚ 6
borkdude 2021-12-09T11:33:34.461Z

Day 9 in #babashka and #clojure https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_d09-clj

miikka 2021-12-09T12:18:57.462300Z

It was a bit too complicated to do in REPL but I did it anyway... here are the choice parts from my REPL history ๐Ÿ˜Ž https://gist.github.com/miikka/48bab1596937814048d0c9fce9f1e4c2

๐Ÿ˜Ž 3
miikka 2021-12-09T12:21:45.462600Z

One day I will start doing the thing where you have a scratch file in the editor and you send to REPL from there... but not today.

borkdude 2021-12-09T12:22:42.462800Z

@miikka It's a sunk cost once you start typing right. But with Rebel Readline you might stay there forever ;)

miikka 2021-12-09T12:24:58.463200Z

That's a good point, I should set up Rebel again. I used to use it, but then I got a new computer at some point and forgot about it

borkdude 2021-12-09T12:26:34.463700Z

to be honest, I haven't used it much either. when I find myself in a console REPL, I just use load-file . But with babashka, I just run the entire file every time... The shell is my REPL :)

miikka 2021-12-09T12:26:52.464Z

Heh, yeah, that's nice about bb

tschady 2021-12-09T13:18:04.471100Z

pretty psyched i was able to only need my grid library from prior years. neigbors, build-grid, connected-adjacency-map https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d09.clj

๐Ÿ‘ 1
borkdude 2021-12-09T13:18:55.471400Z

you were waiting for the grid, weren't you :)

tschady 2021-12-09T13:19:35.472100Z

1 day off ๐Ÿ™‚

genmeblog 2021-12-09T14:25:52.477200Z

basins!

๐Ÿ‘ 1
โค๏ธ 1
๐Ÿคฉ 2
2021-12-09T14:28:08.477600Z

@tws next, a bestagon-based problem

1
๐Ÿ”ฏ 1
๐Ÿ•ธ๏ธ 2
tschady 2021-12-09T14:28:46.477800Z

best shape!

Callum Oakley 2021-12-09T15:13:35.478900Z

time for the annual spike in traffic to https://www.redblobgames.com/grids/hexagons/ ?

tschady 2021-12-09T16:36:48.482300Z

same with http://oeis.org

Sam Adams 2021-12-09T17:24:28.482700Z

Mineโ€™s on the slower side โ€” I didnโ€™t realize that a basin couldnโ€™t have more than one local minimum inside itย https://samadams.dev/2021/12/09/advent-of-code-day-9.html

1
AC 2021-12-09T17:45:43.483Z

I also didn't think about the "one local minimum" fact -- I would have probably done something different. instead I painted each square with a color based on what was "up" or "left" of it and occasionally merging paint colors (when connecting two previously disjoint basins).

Antonio Bibiano 2021-12-09T18:24:01.484200Z

i struggled a lot with stackoverflows a bad recursion ๐Ÿ˜„ https://gist.github.com/antbbn/5907c3c2f733e5156140420b2cb49568#file-day9-clj

Antonio Bibiano 2021-12-09T20:09:35.488500Z

very nice write-up @sam.h.adams

๐Ÿ™‚ 1
1
2021-12-09T20:40:12.489100Z

Part 1

(defn parser [s]
  (->> (str/split s #"")
       (mapv #(Integer/parseInt %))))

(defn find-low-points [input]
  (let [height (count input)
        width (count (first input))]
    (for [w (range 0 width)
          h (range 0 height)
          :let [n (get-in input [h w])
                u (get-in input [(dec h) w] 10)
                d (get-in input [(inc h) w] 10)
                l (get-in input [h (dec w)] 10)
                r (get-in input [h (inc w)] 10)]
          :when (and (< n u) (< n d) (< n l) (< n r))]
      {[h w] n})))

;; part 1
(let [input (->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day9" parser))]
  (->> input
       (find-low-points)
       (mapcat vals)
       (map inc)
       (reduce +)))

2021-12-09T20:41:02.489300Z

Part 2: I find it so confusing working with 2d vectors and reversing the [x y] to [y x]

(defn get-neighbours [input [y x]]
  (let [yx' [[y (dec x)] [y (inc x)] [(dec y) x] [(inc y) x]]]
    (remove (fn [yx] (= 9 (get-in input yx 9))) yx')))

(defn walk-basins [input visited size to-visit]
  (if (empty? to-visit)
    size
    (let [yx         (first to-visit)
          neighbours (->> (get-neighbours input yx)
                          (remove (fn [yx] (or (visited yx) ((set to-visit) yx)))))]
      (recur input (conj visited yx) (inc size) (into (rest to-visit) neighbours)))))

(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day9" parser)
      walk-basin-fn (partial walk-basins input #{} 0)]
  (->> input
       (find-low-points)
       (mapcat keys)
       (map vector)
       (map walk-basin-fn)
       (sort >)
       (take 3)
       (reduce * 1)))

2021-12-09T21:45:37.497800Z

https://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day9.clj here is mine solution for day9, nothing fancy, but this day it helped me to do some crude drawings by using print and println to see that basins are properly covered (a protip (str some-char \u0333) will print this char with a double underscore directly under it so you can print the whole array easily and mark selected elements). It wasn't really that hard but in part 2 I had to realize that you can't too eagerly append cells to visited history as the same cell visited from different neighbours can both count as basin part and not

2
2021-12-09T21:46:42.498800Z

> (str some-char \u0333)ย will print this char with a double underscore directly under Woah! Nice!

2021-12-09T22:04:59.000200Z

yeah, gotta love unicode ๐Ÿ˜„ I am developing mostly using Emacs REPL so not resorting to external tools when doing visualizations is a big plus. this is how it looked printed:

2021-12-09T22:05:26.000500Z

euccastro 2021-12-09T22:24:30.004500Z

today I flooded basins with loop/recur: https://github.com/euccastro/advent-of-code-2021/blob/main/day9.clj

kevinc 2021-12-10T04:54:39.006800Z

https://github.com/kconner/advent-of-code/blob/master/2021/9a.clj Identified low points by rows and by columns, then intersected the sets https://github.com/kconner/advent-of-code/blob/master/2021/9b.clj Flood filling with sets; each recursive step expands the complete border

samedhi 2021-12-09T05:50:06.452200Z

Just finished day 6 and I think the clojure solutions definitely beat out the SQL ones -> https://github.com/mitchellh/advent-2021-sql/blob/main/day06/answer_p2.sql

mauricio.szabo 2021-12-09T12:11:42.461200Z

Are you doing in SQL too? ๐Ÿ˜„

mauricio.szabo 2021-12-09T12:43:33.465400Z

@samedhi my solution in SQL is incredibly faster than Clojure, to be honest: https://gitlab.com/mauricioszabo/advent-of-code-2021/blob/master/src/day-06.sql

samedhi 2021-12-09T15:56:09.481100Z

No, I'm doing Clojure. And wow, your solution seems much less noisy than the one I linked. Impressive.

samedhi 2021-12-09T15:57:02.481300Z

I was talking more on whether I could understand it, yours is much more legible. (Though I have to squint as I am not great at SQL, haha)

samedhi 2021-12-09T05:50:42.452900Z

SQL definitely had a lead on the earlier days... :]

2021-12-09T11:29:31.460500Z

SQL gives me nightmares. I've been hurt by too much bad batshit insane SQL at work.

samedhi 2021-12-09T16:01:31.481600Z

Honestly I very rarely do more than select, insert, update, delete in the most basic ways.

samedhi 2021-12-09T16:03:10.481900Z

I know SQL can be crazy performant if you can ask the right question, but often I just 1. pull all of the data that I need (maybe 1 WHERE clause) 2. convert them to clojure data structures (maps) 3. do some sequence processing stuff 4. write them back to the dabase 5. all within a transaction

mauricio.szabo 2021-12-09T12:23:15.463100Z

Can someone help me with Day 08? I can't understand exactly the problem to be solved, why there are 10 measurements and 4 results, etc...

โž• 1
2021-12-09T12:25:27.463400Z

The ten measurements are the clues you have to use to figure out what the 4 numbers are after the | YOu don't have enough info using just the 4 values

2021-12-09T12:27:05.464200Z

acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf
So here, we know that ab is 1 since it only has 2 "segments" and we know that eafb is four, as it has 4 segments. However, we still don't know what a or b is in 1, a is c or f, and b is c or f.

2021-12-09T12:27:45.464400Z

You need to figure out what all the numbers on the left of the bar are. Once you have figured that out, you can then match them to the four parts after the bar. This will give you a 4 digit number

2021-12-09T12:29:03.464600Z

8                       7                 4          1
acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf
So you know 4 of the numbers, how will you work out the rest ?

๐Ÿ•ต๏ธโ€โ™‚๏ธ 1
2021-12-09T12:30:39.465Z

An important thing is that every line in the puzzle input is an individual problem to solve. The segments are mixed up differently for every line

mauricio.szabo 2021-12-09T12:53:28.465700Z

Yeah, I still don't get it. I know that the left side is supposed to be measurements, and the right side, what's displayed. But why there are 10 measurements to 4 digits?

2021-12-09T12:55:09.465900Z

If there were only the 4 measurements I don't think you would have enough information to figure out what the four digits are. e.g. if you only had cdfeb fcadb cdfeb cdbaf , then i believe their is no way to work out which digits those are

2021-12-09T12:55:32.466100Z

but given the 10 examples on that row, you can work out what the 10 examples are then just match them to the 4

2021-12-09T12:55:56.466300Z

basically you need to only work out the 4 digits to the right, but you need the 10 digits to the left to figure that out

2021-12-09T12:58:07.466500Z

so in the example in this thread, the 4 digits after the bar are 5353. You couldn't figure that using only the 4, I mean, it could be 3535. But with those 10 you can figure out that its 5353

mauricio.szabo 2021-12-09T12:58:09.466700Z

Ah, ok, so the measurements mean that "I gave this measurements, and some of these displayed these numbers, but I don't know which one displayed which number"?

2021-12-09T12:58:17.466900Z

yes

2021-12-09T12:58:34.467100Z

you know ab is 1 as 1 is only the digit that has only 2 segments

2021-12-09T12:59:40.467800Z

but a 1 should be

....
.    c
.    c
 ....
.    f
.    f
 ....
So you need to figure out if a is c or f

2021-12-09T13:00:06.468Z

hint: Certain numbers are subsets of other numbers, and some numbers are supersets of other numbers.

2021-12-09T13:04:38.469200Z

You don't actually need to figure out exactly what characters match to what segments. You can just figure out what "words" relate to what numbers

tschady 2021-12-09T13:30:48.473900Z

the left side represents the digits 0->9 (in some order), in that linesโ€™ particular cipher

โœ… 1
mauricio.szabo 2021-12-09T15:29:46.480800Z

Ah, ok, thanks ๐Ÿ™‚.

Antonio Bibiano 2021-12-09T12:59:39.467700Z

sorry peeps, i need some help with day 9 potential spoilers in thread

Antonio Bibiano 2021-12-09T13:00:06.468200Z

for part 2 I ended up with this recursive function

Antonio Bibiano 2021-12-09T13:00:28.468400Z

(defn get-basin [heightmap points]
    (into #{}
          (mapcat (fn [point]
                    (let [basin-neighbors (get-basin-neighbors heightmap point)]
                      (if (empty? basin-neighbors)
                        [point]
                        (conj (get-basin heightmap basin-neighbors) point))))
                  points)))

Antonio Bibiano 2021-12-09T13:01:37.468600Z

get-basin-neighbors returns a list of neighbors that can be in the basin, ie no 9 and not the point itself

Antonio Bibiano 2021-12-09T13:02:10.468800Z

the heightmap is a nested vector of the numbers

Antonio Bibiano 2021-12-09T13:02:20.469Z

works for the example input but i get a stack overflow error on the large input

miikka 2021-12-09T13:09:28.469600Z

Hmm; I'm a bit surprised that it works with the small input since it looks like it would end up in an infinite loop in both cases

miikka 2021-12-09T13:10:13.469800Z

If you have a point and then you call get-basin on its neighbours, doesn't that call end up calling get-basin on the original point?

Antonio Bibiano 2021-12-09T13:13:43.470Z

i only get the neighbors where the number is higher than the current one

Antonio Bibiano 2021-12-09T13:15:02.470200Z

it's true that it does some unnecessary calculations

Antonio Bibiano 2021-12-09T13:15:13.470400Z

but it should end up in an infinite loop

miikka 2021-12-09T13:15:32.470600Z

Oh, okay

miikka 2021-12-09T13:17:59.470900Z

I wonder if the big one just has too big basins, then, for the recursion to work (without using loop/`recur` )

genmeblog 2021-12-09T13:19:07.471600Z

the biggest basin in my dataset is 98

Antonio Bibiano 2021-12-09T13:19:45.472300Z

does the fact that I pass the heightmap as an argument make things worse?

genmeblog 2021-12-09T13:20:14.472500Z

rather not

miikka 2021-12-09T13:28:15.473200Z

With mapcat in play, I don't have super clear feel about the recursion depth but seems like it could work ๐Ÿคทโ€โ™‚๏ธ

genmeblog 2021-12-09T13:28:16.473400Z

get-basin-neigbours can return the same neighour for diffent input

genmeblog 2021-12-09T13:29:04.473600Z

and you visit the same points many times

miikka 2021-12-09T13:30:49.474100Z

Hmm, if get-basin-neighbors only goes uphill, seems like you'd get wrong result for a basin with two low points. But that's a separate issue from the stack overflow

Antonio Bibiano 2021-12-09T13:34:17.474700Z

yeah @tsulej i thought it would be harmless, but maybe not ..

Antonio Bibiano 2021-12-09T13:34:54.474900Z

i'll try a loop/recur refactor and to make it less wasteful

miikka 2021-12-09T13:35:29.475100Z

Oh, the problem statement says that each point belongs to only one basin, so what I said is not an issue

Aleks 2021-12-09T13:42:52.476100Z

@antbbn BFS

sarcilav 2021-12-09T14:12:08.476400Z

maybe this it the problem > i only get the neighbors where the number is higher than the current one

sarcilav 2021-12-09T14:14:08.476600Z

what it is the output of something like

012190
232299
111111

sarcilav 2021-12-09T14:14:18.476800Z

on your code @antbbn

sarcilav 2021-12-09T14:14:37.477Z

or your basins better

Antonio Bibiano 2021-12-09T18:04:29.483200Z

thanks for your help! I did it

(defn get-basin-new [heightmap points]
  (loop [ret #{} points points]
    (if (empty? points)
      ret
      (let [cur-point (first points)
            basin-neighbors (remove ret (get-basin-neighbors heightmap cur-point))]
        (recur (conj ret cur-point) (concat (rest points) basin-neighbors))))))

Antonio Bibiano 2021-12-09T18:06:47.483400Z

turns out visting the same place many times was really messing with the recursion!

Antonio Bibiano 2021-12-09T18:07:27.483600Z

@sarcilav that's a very valid concern, but I think the input is simpler for today

Antonio Bibiano 2021-12-09T18:16:35.483800Z

ah wait the second if is not necessary! refactored

Antonio Bibiano 2021-12-09T18:24:36.484400Z

@zelark is that similar to what you pointed me to with BFS?

Aleks 2021-12-09T19:06:04.484700Z

@antbbn, yes https://en.wikipedia.org/wiki/Breadth-first_search

Antonio Bibiano 2021-12-09T19:11:45.486Z

ah yeah that's where I ended up

Antonio Bibiano 2021-12-09T19:12:27.486900Z

Looks like I could have used a queue here

๐Ÿ’ฏ 1
Antonio Bibiano 2021-12-09T19:12:41.487100Z

but didn't see any solution using queues

Aleks 2021-12-09T19:19:09.487700Z

Once, I implemented my own a minesweeper game. Does it look similar to todayโ€™s problem? ๐Ÿ™‚

๐Ÿ˜„ 1
2021-12-09T19:12:13.486600Z

For day 9 part 2, when walking the basins, do you want to only include the squares that are within 1 of the current square, e.g. If you were at 5 here, would valid neighbours for the walk be only the 6s or the 8s too ?

peterc 2021-12-09T19:14:10.487300Z

6s and 8s

2021-12-09T19:14:17.487500Z

thanks!

2021-12-09T20:38:40.489Z

Everytime you refresh the 2021 page the waves change ๐Ÿ™‚

3
tschady 2021-12-09T20:56:36.490400Z

for extra motivation. when you complete the year you get that continual animation

lread 2021-12-09T21:39:28.496700Z

This is my first year trying the Advent of Code. I am finding the puzzles tremendous good fun. For all you veterans, do you typically complete all 25 days?

2021-12-10T13:20:38.020400Z

I did all the stars last year while being busy because I failed at giving up.

2021-12-10T13:21:07.020600Z

That's addictive after a couple of weeks.

miikka 2021-12-10T16:45:14.025700Z

I usually do only the quick ones. If the top list times are >15 minutes, then I probably won't bother ๐Ÿ˜›

lread 2021-12-10T19:40:25.034Z

I feel kind of hooked right now. But the shine might come off after the puzzles become much more puzzling.

tschady 2021-12-09T21:46:12.498600Z

i do 50-100% depending on my schedule, then chip away at problems that interest me during the year. i think iโ€™ve done 2/3 of all so far.

tschady 2021-12-09T21:47:04.499Z

thereโ€™s a considerable time ramp up around the 15th

2021-12-09T21:47:34.499200Z

The best I've ever done was last year, 36 stars.

2021-12-09T21:47:51.499400Z

And a chunk of those 36 were done this year

lread 2021-12-09T21:49:55.499600Z

Good to know, thanks, so it is a gift that can keep on giving, even into the new year!

tschady 2021-12-09T21:55:46.499800Z

2015 is the easiest year, i think. good place to start.

lread 2021-12-09T21:58:07Z

Oh right... I could visit puzzles of advents past. Interesting...

Phil Shapiro 2021-12-09T22:10:08.003800Z

2020 seemed easier to me than 2019 and 2018. Or maybe I'm getting better at writing advent code :). Most people don't complete the full calendar, you can look at the stats for each year to see completion rates per day.

2021-12-09T22:16:14.004Z

Yeah, I agree 2020 feels the easiest year so far.

2021-12-09T22:17:12.004300Z

This year feels easier than 2020 though, up until this point.

fingertoe 2021-12-10T00:08:05.005800Z

The first year I did 7, the second year, 13, This year I am 10 for 10.. As the holidays approach, there is a lot more competition for attention.. (also my wife isn't fond of obsessed coding guy).