This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

## 2021-12-05

## Channels

- # adventofcode (111)
- # announcements (20)
- # babashka (19)
- # beginners (47)
- # calva (7)
- # clojure (56)
- # clojure-dev (27)
- # clojurescript (2)
- # events (1)
- # holy-lambda (1)
- # juxt (2)
- # meander (18)
- # minecraft (4)
- # missionary (107)
- # nextjournal (21)
- # off-topic (30)
- # reagent (7)
- # reitit (19)
- # releases (1)
- # tools-build (8)
- # tools-deps (7)
- # vim (22)
- # xtdb (4)

🧵Day 5 answers thread: post your answers here

I'm sure if I remembered my linear algebra at all, I'd have a cleverer way of getting the points on a line (the degenerate cases were easy with `for`

comprehension). But this'll do.
https://coyotesqrl.github.io/advent-of-code/2021/#/src%2Fcoyotesqrl%2F2021%2Fday5.clj

I am also curious if there is a geometrical property that can help to avoid generating points

@U01GXCWSRMW I wrote an almost identical version of your move-fn (picking dec, inc, or identity as a 'step' function)

```
(defn step-fn [a b]
(cond (> a b) dec
(< a b) inc
:else identity))
```

Once again, it's not concise, but I had fun with `letfn`

and `some-fn`

, so this was a terrific learning experience. Looking forward to reading your solutions... tomorrow...
https://github.com/abyala/advent-2021-clojure/blob/main/docs/day05.md

@U0124C56J5R I had initially been using `range`

for the degenerate cases, but gave up on it when I went to diagonal. I just constantly forget I can call `map`

over multiple collections.

Inspired by @U076FM90B solution.

@U1NLKFVC4 in my solution it is the same ^_^

My solution (no clean up, I prefer to show it raw) https://github.com/green-coder/advent-of-code/blob/master/src/aoc_2021/day_5.clj

My goal was to introduce Clojure to the viewers, so I didn't try to do anything complicated (i.e. simplify the program, in fact 😄 )

Nice use of `frequencies`

again

https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day05.clj and (rather boring) https://github.com/RedPenguin101/aoc2021/blob/main/day05.md
Is there a function that does a sort of `take-until`

? i.e. take-while but on matching the predicate it will terminate the sequence? Easy enough to write with a `reduce`

but feels like something that might be in the standard library, or there's a way to use the standard library to do that.

most interesting part for me was figuring out how to draw the line segment in a way which works for horizontal, vertical, and diagonal, and only hits the integer points without having to do any filtering. the metric you want is the https://en.wikipedia.org/wiki/Chebyshev_distance! https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/05.clj

ah I see @U8MJBRSR5 did the same thing :)

Ended up implementing specialized version of range which can be used to expand horizontal, vertical and diagonal lines:

```
(defn range* [start end]
(cond
(< start end)
(range start (inc end))
(= start end)
(repeat start)
:else
(reverse (range end (inc start)))))
(defn expand [[[x1 y1] [x2 y2]]]
(map (fn [x y] [x y]) (range* x1 x2) (range* y1 y2)))
```

https://github.com/rap1ds/advent-of-code-2021/blob/main/src/day5.cljMy day 5: https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_05-clj

expecting more line stuff, so I’m considering abstracting this into Line protocol. went with slopes/intercepts. https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d05.clj

this is my solution for today

I was unsure about the cond in my `range*`

.. but then the i would have had to do some kind of conditional for straight lines so might as well put it there

if the input was a single point I would be screwed 😄

Not so dirty today ^^ https://github.com/v-garcia/aoc_2021/blob/main/day_five.clj

for those doing `range*`

type stuff, might simplify to:

```
(defn range* [x1 x2]
(let [dx (compare x2 x1)]
(range x1 (+ dx x2) dx)))
```

aaaah nice, was looking for that!

I've considered it for a moment but didn't try, was waried about edge case when dx is 0

~~looks like it's exactly what I wanted in my case~~
mhh maybe not
`(range 3 3 0) => ()`

https://gist.github.com/stuartstein777/73f42275324d7c06b6d3510fd70e4229 ALso couldn't think of a nice general way to get points on a diagonal line given (x1,y1), (x2, y2)

strange that the stats show less completions today than day 4, thought today was a LOT easier than yesterday

@U0105JJK1L3 take until could be implemented like `take-while (complement pred) coll`

?

I agree with @U1Z392WMQ that I will probably end up pulling `line-pnts`

to a common namespace.

The alternative to `(compare x1 x2)`

is to `(sort pnts)`

. If your points are vectors, they will sort exactly like you would want.

Generating the points and using a map to track count https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day05.clj

https://github.com/maxminoS/advent-of-code/blob/main/2021/src/aoc2021/puzzle09.clj took 9 whole minutes to solve this

It probably takes me a minute to parse the question and understand what I need to do, then no way can i code it up in 2 minutes... The leaderboard times are incredible

made the mistake of creating the map and plotting each point to the map, now i see that many people just found the frequency of the points and could get the solution

These threads are great, Its really helpful being able to see other peoples solutions in clojure after I finish mine. Can pick up some neat functions

my (slow) solution for today https://gist.github.com/galuque/b0a932f8b262c3b6b9f993383ae61ea5

re: avoiding having to deal with infinite slope
You don’t **have** to work in terms of slope at all. To be clear I don’t think there’s anything wrong with using slope and handling the divide by zero explicitly, but here’s another way of thinking about it that avoids the infinite slope awkwardness:
Given a line starting at `s`

and finishing at `f`

(`s` and `f`

vectors), the line segment between them is

`s + t * (f - s) for t real between 0 and 1`

I like this representation for problems like this, because there’s no special case for the vertical line (unlike if you try to use `y = m*x + c`

).
Now the only awkward thing is that we want integer coordinates. `(f - s)`

is always of the form `[n 0]`

, `[0 n]`

, `[n n]`

, `[n -n]`

for integer `n`

since we’re given that the line is always horizontal, vertical, or at 45deg. In every case we get integer coordinates exactly when `t`

is `k/n`

for some integer `k`

between `0`

and `n`

inclusive. So we can rewrite our line segment as
`s + k * (f - s) / n for k in {0, 1, ..., n}`

or, if you want to expand it out
`[sx + k * (fx - sx) / n, sy + k * (fy - sy) / n] for k in {0, 1, ..., n}`

(and it just so happens that `n`

is the “length” of the line if you use the Chessboard Distance as I mentioned above, but that’s besides the point really)

no infinity problems if you convert to polar, ha

```
(defn theta [[[x1 y1] [x2 y2]]]
(Math/atan2 (- y2 y1) (- x2 x1)))
```

my solution for today would be marginally nicer if `range`

behaved as one would guess from the docstring

```
When step is equal to 0, returns an infinite sequence of
start. When start is equal to end, returns empty list.
```

but it turns out that if step is zero *and*start equals end, you get the empty list. https://github.com/euccastro/advent-of-code-2021/blob/main/day5.clj

@U076FM90B: great one! if you want to use more standard functions, `(compare end start)`

is the same as your `(direction start end)`

, and `(complement diagonal?)`

would be the same as `(comp not diagonal?)`

`compare`

is cool, but I was woried about edge case when 2 numbers are equal, the `range`

function needs non zero step. Another concern was that `compare`

does not guarantee 1 or -1 just positive or negative number. In the end I didn't try it because of those concerns

@U65FN6WL9 not exactly, `(compare end start)`

will return 0 if start and end are equal, whereas `(direction start end)`

will return 1.

Also, what is wrong with `complement`

? It is from the core. ^_^

oh boy.. now I wanna know when it *doesn't* resturn 1 or -1 😄

Yeah @U076FM90B brings up a legit concern w/ `compare`

. I didn’t say it earlier and should have, but there’s nothing in the contract w/ compare that says it will return -1 or 1.

@U01HY37QQUA I saw that for strings it returns bigger numbers https://clojuredocs.org/clojure.core/compare

From the `Comparable`

docstring:
> Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

It’s not a big deal for AoC, but people should probably be aware of the general applicability.

thanks! and sorry, I should have read the whole thread before commenting at least; there was already talk about range and compare

@U067R559Q are you asking me or @U076FM90B? I do suggest using `complement`

late solution: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day05.clj

Nice to see I have come to a similar solution than others and not that ugly mess I did the last days. 😆

after day 3 and 4, really happy with how clean mine came out https://github.com/FelipeCortez/advent-of-code/blob/master/2021/05.clj

https://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day5.clj - went fairly quickly, but then got wrong results for part2 and lost traction for a while but then noticed that my naive algorithm of conversion straight line -> points generates way too much points for diagonals so wrote another naive algo to generate points for diagonals 😄

Day 5. Couldn't figure out how to solve without brute forcing and generating all coordinates on the line.

```
(def puzzle-input
(-> (str/split (input "day5.txt") #"\n")))
(defn coordinate [coord-str]
(let [[x1 y1 x2 y2] (mapv read-string (re-seq #"\d+" coord-str))]
{:x1 x1 :y1 y1
:x2 x2 :y2 y2}))
(defn vertical-or-horizontal? [{:keys [x1 y1 x2 y2]}]
(or (= x1 x2) (= y1 y2)))
(defn *range [a b]
(if (> b a)
(range a (inc b) 1)
(range a (dec b) -1)))
(defn generate-line-coords [{:keys [x1 y1 x2 y2]}]
(->> (cond
(= x1 x2) [(repeat x1) (*range y1 y2)]
(= y1 y2) [(*range x1 x2) (repeat y1)]
:else [(*range x1 x2) (*range y1 y2)])
(apply mapv (fn [x y] {:x x :y y}))))
(defn overlapping-points [coordinates]
(->> coordinates
(mapcat generate-line-coords)
(sort-by (juxt :x :y))
(partition-by identity)
(filter #(>= (count %) 2))
(count)))
(defn part-one [puzzle-input]
(->> (mapv coordinate puzzle-input)
(filter vertical-or-horizontal?)
(overlapping-points)))
(defn part-two [puzzle-input]
(->> (mapv coordinate puzzle-input)
(overlapping-points)))
(comment
(part-one puzzle-input)
(part-two puzzle-input))
```

Do we think the avent of code leaderboards time are in any way indicative of how fast people get code written at work?

From one perspective code at work is just code, they are fast there too. But code at work is a team activity if team cannot read the code it slows down everybody

Also the starting time doesn't help everyone, I don't think everyone stays up until midnight or wakes up at 6am (GMT+1 europe for example) to tackle the challenges

Last task I had at work, it took me 2days. That was from nothning to finishing the coding (day and a half), testing (1/4 day), writing documentation (1/4 day). I'm just wondering if these people that top the leaderboards would be able to code up in an an hour or so what took me a day and a half

I suspect they have a very specific setup for quickly manipulating the types of inputs you typically get in the AoC

last year I read this blogpost https://blog.vero.site/post/advent-leaderboard

Welcome to the world of competition coding! There are definitely some skills of competition coders that carry over: familiarity with the IDE, knowledge of the language, deep understanding of many different algorithms and data structures (and able to implement them), and perhaps most importantly, passion for coding. Speed doesn't necessarily equate with value though. In practice, we often trade speed for quality.

I think this came up in clojureverse or somewhere in a similar context: https://catonmat.net/programming-competitions-work-performance

maybe watch the video but don't read the article; there's a huge caveat to it: Norvig is talking about Google employees, which sets a pretty high baseline for programming performance already

1 - The leaderboard probably correlates to time zones more than anything else.. 2 - I can (and do) often get a right answer with a very incomplete program, especially with the REPL. I think the leaderboard is nice for chasing down folks github repos to see if you can learn anything from their approaches though.. It also may give some motivation to keep going..

It might be indicative of how fast people can write code, but it’s definitely not related to productivity/adding value/anything that other people actually care about.

not knowing anything else, would you hire a random programmer or a random person from the leaderboard? and why?

Ok. I don’t think you realize what you’ve done. You’re about to get a lot of opinions.

First, the answer to your question: Realistically, I would hire neither. That would be irresponsible.
But the interesting bit of the question is: Are you *closer* to hiring a leaderboarder or a rando?

One necessity of a programmer is, well, the ability to program. Obviously a leaderboarder proves this ability. Rando might possibly be in that far-left tail that actually cannot program at all. More likely that they are somewhere close to the median, but you never know. So in this regard, the leaderboarder is ahead.

However, there is a non-trivial subset of programmers that are very good at talking to the computer and very bad at actually solving problems.

These people go by different names. I often call them “tinkerers.” I heard Bryan Cantrill refer to them “compiler people” in a talk.

I have found that these people usually cause *far* more harm than good. And they’re *far* more nefarious, because they are often very, very busy-looking.
They hurl code, knock out cards, pull late nights, get the job done.
In other words, they are extremely attractive to a certain kind of manager. That makes it *extremely* difficult to reasonably discuss the long term effects of their behavior.

The fact that someone can finish an AoC in 3:50 puts them firmly in the “might be a tinkerer” category.

The downside risks of people in this category are so high, that it completely negates any advantage they have compared to the rando who might not be able to code at all.

Not strongly related, but I’d be hard pressed to believe that the people on top of the leaderboard aren’t better at coding in general (this is a very vague notion) than the average programmer. The only way that would make sense, is that if those people write code at work the same way they do at competitions, which isn’t a charitable view of them.