Fork me on GitHub

🧵Day 5 answers thread: post your answers here

R.A. Porter07:12:21

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.


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))

👍 1
Andrew Byala07:12:04

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...

R.A. Porter07:12:23

@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 ^_^


Yeah I just realized that looking at your solution!


I was very surprised how close I was to the alekszelark's

😁 1
Vincent Cantin09:12:16

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 😄 )

Vincent Cantin09:12:31

Nice use of frequencies again

Joe10:12:11 and (rather boring) 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.


Oooh, that step in range would've saved me some hassle, totally forgot about that.

Callum Oakley11:12:42

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!

👍 6
👀 1
Callum Oakley11:12:13

ah I see @U8MJBRSR5 did the same thing :)

Mikko Koski12:12:50

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

(defn range* [start end]
    (< start end)
    (range start (inc end))

    (= start end)
    (repeat start)

    (reverse (range end (inc start)))))

(defn expand [[[x1 y1] [x2 y2]]]
  (map (fn [x y] [x y]) (range* x1 x2) (range* y1 y2)))


expecting more line stuff, so I’m considering abstracting this into Line protocol. went with slopes/intercepts.

👍 3
Antonio Bibiano13:12:54

this is my solution for today

Antonio Bibiano14:12:10

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

Antonio Bibiano14:12:46

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


Not the prettiest. But it works.


for those doing range* type stuff, might simplify to:

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

👍 8
Antonio Bibiano14:12:06

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

Antonio Bibiano14:12:29

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

Stuart14:12:04 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


hangover effect

Antonio Bibiano14:12:42

@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.


too useful for AoC


The alternative to (compare x1 x2) is to (sort pnts). If your points are vectors, they will sort exactly like you would want.


But yeah, no way around checking for undefined slopes.


Much easier than day 4 IMO


Number 1 on the leaderboard today solved both parts in 3:02!😮

😱 1
max minoS16:12:57

nice! saw your solution and it just makes my solution more horrible


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


From start to submitting right answer to part 2 today probably took me an hour ish

max minoS16:12:06

mine took 9 minutes to run, couple hours to write probably

max minoS16:12:22

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

Callum Oakley17:12:22

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}

👏 2
Callum Oakley18:12:02

(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)

👍 1

no infinity problems if you convert to polar, ha

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

🐻‍❄️ 5

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.

☝️ 1

@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?)

👍 1

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

✔️ 2

@U65FN6WL9 not exactly, (compare end start) will return 0 if start and end are equal, whereas (direction start end) will return 1.

👍 1

Also, what is wrong with complement? It is from the core. ^_^

Antonio Bibiano19:12:16

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


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.


People do things like (- this that).


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

👍 2

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


I have a silly reason, comp not is just shorter than complement 😂

🙂 1
😅 1

what a mess!

🤯 1

Wasnt aware of Clojure2d, looks cool

👍 1

(I'm the author btw)


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

🎉 3

after day 3 and 4, really happy with how clean mine came out

👍 1
karol22:12:03 - 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 😄

Mario C.22:12:46

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))

(defn part-one [puzzle-input]
  (->> (mapv coordinate puzzle-input)
       (filter vertical-or-horizontal?)

(defn part-two [puzzle-input]
  (->> (mapv coordinate puzzle-input)

  (part-one puzzle-input)
  (part-two puzzle-input))


@U65FN6WL9 oh, sorry, I didn’t parse it correctly 😊

👍 1
🙂 1

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

💯 1

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

Antonio Bibiano16:12:15

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


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:


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.

☝️ 2

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

bananadance 1

This is a really good question. Let me think on it.


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

😂 1

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?


I think the answer both are equally close to being hired, but in different ways.


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.


I don’t think there’s any conflict between this and what I said.


(Not sure if you thought there was or not.)