
I was pleased with <https://github.com/lojic/LearningRacket/blob/master/advent-of-code–2021/solutions/day06/day06.rkt|my Day 6> - I did try and make it concise, but I don’t think I “golfed” it. I suppose that’s in the eye of the beholder though. I really tried to find a math solution, but either I don’t have the chops, or there isn’t a clean one.

@massung it looks like you may have posted Bogdan’s repo my mistake above.


Nice! Curious why the line break after gamma
, but not epsilon
in solve-part1
?

No idea :) this is @sorawee ‘s formatter

I suppose that @ben.knoble ran this in Discord. I configured raco fmt
in Discord to have width limit of 75 characters, so that it fits the message area of Discord. This width limit is why it breaks on gamma
but not epsilon
.

More formally, the code formatter will attempt to format code in a way that minimize the number of lines, subjected to the constraint that the code fits the page width limit. That means it prefers
(let ([xxx yyy])
zzz)
since it has fewer lines, but if both being in the same line causes the line to overflow, it would need to switch to:
(let ([xxx
yyy])
zzz)
instead.

I thought I had a nice mathy solution, but it wasnt fast enough. Then I saw a matrix-exponent + matrix-vector solution, and I’m working on porting it; fingers crossed it runs quickly. Part1 i have in 5ms, but part 2 was just too slow

@kristian.lundstrom has joined the channel

A friend showed me his solution and I feel sooo stupid right now. Mine’s plenty fast (~4ms) for part 2, but his shows why the puzzle drops at midnight aren’t ideal :slightly_smiling_face:

Recoding mine now to see the difference

Yep. Simpler and runs in 1ms now instead of 4

How I felt…

I’ve also thought about switching the hash for a vector, but the hash version already takes less than 1ms on my machine so I didn’t bother :smile:

I ended up golfing my main version a little too much, so for penance, here’s <https://github.com/lojic/LearningRacket/blob/master/advent-of-code–2021/solutions/day06/day06-annotated.rkt|an annotated version> that’s much more readable. Poor Ben is sometimes getting my commentary twice since he’s in our local slack also :)

Funny how your mind goes to a solution right away and how it influences things. I went straight to “there’s gotta be an equation for this” and just couldn’t shake it.

Loo no worries Badkins :) still upset my clever version is too slow for part 2

Actually, it barfed: map: contract violation
expected: list?
given: '((23 (155 148 141 134 127 120 113 106 99 92 85 78 71 64 57 50 43 36 29 22 15 8 1)) (22 (148 141 134 127 120 113 106 99 92 85 78 71 64 57 50 43 36 29 22 15 8 1)) (21 (141 134 127 120 113 106 99 92 85 78 71 64 57 50 43 36 29 22 15 8 1)) (20 (134 127 120 ...
context...:
/Applications/Racket v8.2/collects/racket/private/map.rkt:257:2: gen-map
/Users/Knoble/Library/Racket/8.2/pkgs/qi/flow.rkt:161:5
/Users/Knoble/Library/Racket/8.2/pkgs/memoize/memoize/main.rkt:71:19: count-generations
/Users/Knoble/code/advent2021/day6/solution.rkt:59:0: count-all-generations
/Applications/Racket v8.2/collects/racket/private/list.rkt:321:16: composed
/Applications/Racket v8.2/collects/racket/cmdline.rkt:191:51
body of (submod "/Users/Knoble/code/advent2021/day6/solution.rkt" main)
Even though I’m sure it’s a list. Lol. Whatever. Changing it anyway when I have time.

> Funny how your mind goes to a solution right away and how it influences things. The worst part is you just know it’s probably not that complicated and that you should just “reset”, but end up digging deeper instead. Or maybe that’s just me :smile:

So, my <https://github.com/Bogdanp/aoc2021/blob/master/day06.rkt|hash version> takes 220μs on my machine and I wanted to see how <https://github.com/Bogdanp/aoc2021/blob/f46abd0c2e23a502c4b1d7f26787af2147ccb330/day06-fxvector.rkt|an fxvector version> would fare. It does it in 11μs!

So, i was timing parsing, too. Here’s w/o the parsing: CL-USER> (let ((ages (first (real-data #'parse-ages))))
(time (count-fish ages 256)))
Evaluation took:
0.000 seconds of real time
0.000110 seconds of total run time (0.000109 user, 0.000001 system)
100.00% CPU
0 bytes consed

I went straight to vector, but I didn’t try to solve before bedtime :smile:


In mine, for any given fish I calculated how many “1st gen spawns” would occur just using division, then did a recursive call for each spawned fish, using a hash to cache previously calculated answers. Finishes in < 1ms on my machine https://github.com/otherjoel/advent-of-code/blob/main/2021/day06.rkt\|https://github.com/otherjoel/advent-of-code/blob/main/2021/day06.rkt

@joel - that was my first solution as well

I should’ve run raco fmt --help
:) I’ll experiment with widths. Thanks for the tool @sorawee !

I prefer: (~> (file->string "day06.txt")
string-trim
(string-split ",")
(map string->number _))
over the fmt
reformatted: (~> (file->string "day06.txt") string-trim (string-split ",") (map string->number _))
but I expect it’s impossible to please every one :)

This is using the default formatter. You can also write additional instruction to say that ~>
should be formatted that way, and it will always format the code that way.

Interesting @samdphillips - I looked in the vector doc for a vector-update!
- I see you just coded your own :)

I don’t know why there isn’t a version in the stdlib

See how to use the API to write this additional instruction at https://docs.racket-lang.org/fmt/, but note that the interface is unstable.

#lang racket
(require fmt)
(define code #<<EOF
(~> (file->string "day06.txt") string-trim (string-split ",") (map string->number _))
EOF
)
(define (my-formatter-map s)
(case s
[("~>") (standard-formatter-map "require")] ; format `~>` like how we format `require`
[else #f]))
(display (program-format code #:formatter-map my-formatter-map))
results in:
(~> (file->string "day06.txt")
string-trim
(string-split ",")
(map string->number _))

Ok, I spent way too much time refactoring my solution today, so I’d like some feedback from fellow Racketeers re: the readability of <https://github.com/lojic/LearningRacket/blob/master/advent-of-code–2021/solutions/day06/day06.rkt|this solution> - does it seem reasonable to you?

(credit for using vector-update!
goes to Sam :) )

Cool - thanks!

Assuming iterate f n x computes f^n(x), yeah, I think that’s quite readable. I might put the vrs on separate lines so it’s easy to spot differences at a glance.

Knowing the solution obviously helps w/ readability. The real question is can someone who knows the problem, but is looking at your solution to learn how to do it, able to follow?
The threading is nice. I think the vector iteration (line 15) would be confusing, though.
Side note: I’m always a bit confounded as to why racketeers use define
lexically instead of let
and lambda
:slightly_smiling_face:

Personally I do it because it often avoids a needless level of nesting/left-drift.

Coming from CL originally, seeing define
lexically feels like (although it absolutely isn’t) a code smell. Since in CL defun
is a macro that expands to global scope. I have to double and triple-take every lexical define in Racket.

I get that and I’ve evolved at least an instinct to tuck everything away like that. I’m trying to find the passage (it might have been something of Matthew Butterick’s) that tipped me in favor of the clarity of lexical define early on.

@massung I usually use let
way more than define
compared to most Racket folks. Not exactly sure why I used define
for vr

I like being able to select the entire let
as a unit i.e. the variables and code that uses the variables

@massung good point about separate lines for the vr
clauses. I know it’s silly, but when coding up solutions for things like AoC, I think I subconsciously always try to minimize line count

I replaced the define
with a let
. I tried separate lines for all the vr
clauses, and I couldn’t accept that much vertical space :) Also, the function returns a single vector, and that line seems similar to a vector literal e.g. #(0 1 2 3 4 5 6 7 8)
so I think I’m ok with it.

Day 7 spoilers


Longer than it needs to be. Brute force is quick enough, assuming summations are computed instead of looped. But I wanted to be a bit more elegant, so I treated the problem like a normal distribution and basically only checked targets within [-z,+z]
and it dramatically sped up. Using z=0.5
worked for all data. On the real data I could take it all the way to z=0.1
and get the right answer and the time went down to a couple ms.

I’d be interested in other ideas people had for minimizing the search space.