16
votes
Day 2: Red-Nosed Reports
Today's problem description: https://adventofcode.com/2024/day/2
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python
with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
Today's took me a bit longer for the second part because I misunderstood the change and for some reason thought if there was a single bad level I could simply remove it without checking if the new report is safe.
Once I realized my mistake it was pretty straightforward.
My only real annoyance with Rhai so far is that there's no good mode for emacs for it.
I found an old one someone made, but the way it handles the indentations is really janky.
It seems like it's sort of trying to line the indentation up with the first letter of the second token on the line above and if that fails, it just does a massive amount of indentation.
So I've got anywhere from two to four spaces of indentation depending on the line.
Rhai Code
Edit: I made it more compact and moved the
get_input
function to a separate file since it'll be used every day.Rhai Code
There's probably a smarter way to do part 2... but I couldn't be bothered to figure it out. The brute-force method was good enough for me.
Incidentally, there should really be a
sign()
implementation in theMath
module. Not that it's hard to write one myself - it just feels like an odd gap in the standard library.Solution (Jai)
Now that I'm off work I can post my solutions:
Part 1
Part 2
Part 2 took me a while because I was trying to be cute. I gave up and just brute forced it which seemed to work well enough. I'm still trying to get used to Python. For those who know, is there a cleaner way for me to convert my list of strings to a list of ints? I'm still stuck in functional Javascript world and want to use maps everywhere, but maybe there's an easier or more idiomatic way to do it.
I don't know if there's that much of an easier way, but the main idiomatic difference would be using list comprehension instead of mapping.
Here's a one-liner if you want which would leave you with a list of lists of ints:
You can also use
map
, as you've done, though I'll note you can actually just passint
as a function, rather than writing a lambda:Last little idiomatic tip, you probably want to avoid using
input
as a variable name, as it overshadows the built-in function of the same name.Wonderful, thank you very much!
So far keeping up OOP and TDD! This took... far longer than it should have, but I'm definitely learning more about Smalltalk. Discovering
overlappingPairsCollect
andcopyWithoutIndex
handled a lot of the heavy lifting here. Also, Pharo shows little green dots when the tests pass, and getting them all to light up is a wonderful way to tie problem completion to dopamine release.I think I'll have to swap to just posting a github link and snippets going forward. Getting to a somewhat reasonable length means cutting out the comments, protocols, accessors, tests...
Smalltalk Solution
I'm using Rust again this year.
I considered trying out Julia, but I don't want to be fighting both the puzzles and the language.
Code
The code is a bit inefficient, but with sub-millisecond runtimes, I'm not sweating that.
Part 1
Edit: After some more refactoring:
Part 2
Solved in the most-naive way possible -- by just deleting each number in turn
and checking if that makes the report safe.
Julia has been really tempting to me as well - I come from a MATLAB background, and julia does have a really nice Control System library available.
Me right now trying to learn Racket, but it's fun :P
You could be regretting your choices come day 18 or so, though. ;-)
Took me a while ago but I think I'm sorta kinda getting the hang of some basic Racket programming. I spent a while trying to figure out smarter ways for both parts but even as it is, running both (and printing) only takes 0.225s on my machine.
Racket solution
Once again, anyone who knows Racket can feel free to tell me what I did that not idiomatic (or just what's inefficient, too).
Comment 1
You've specified
#lang racket
and used(require racket/base rackunit)
-racket/base
is redundant since it's a subset of#lang racket
Comment 2
Since
tolerant-safe?
already callssafe?
I think(or (safe? report) (tolerant-safe? report))
cab be(tolerant-safe? report)
. That way you could replace the fold's in both parts withcount
ah.. ah.. aaaahComment 3
I was unaware of
for/list/concurrent
so thanks for introducing me to that! Does it buy you anything reading from a port though. Isn't the port a shared resource between all the threads? I'll have to experiment myself with that.Thanks!! For comment 3, no clue, I just saw it when I was searching the racket docs and tried it 😂
I should probably spend some time going through the rest of the guide, I basically saw ports are how to do I/O and then used it, that was it. :P
Step-by-step explanation | full code
My key today was realizing a strictly increasing list is the same as a strictly decreasing one, just reversed. Otherwise, pretty straightforward today thanks to Python's
any
andall
functions! Nice way to practice writing pure helper functions foris_safe
andis_strictly_increasing
.Back again writing lisp!
The code for today is definitely worse than on day 1, and I spent a silly amount of time trying to over engineer a problem dampener to blow a fuse at the first sign of an error rather than doing the naive solution.
That said, I spent a lot less time tripping over the language today, although I did get confused about some finer points of loops and appending to lists
My code
Elixir
I thought for a while about what a "smart" approach for part 2 would look like, but then I tried out the brute-force approach since it was a one-liner, and it ran in a few hundred microseconds so... seems good!
Both parts
In
safe_p1?
, theStream.scan
call lazily checks each pair of numbers, emitting:not_safe
if any pair is invalid. (The other values it emits aren't important as long as they are something other than:not_safe
.)The
Enum.any?
call stops and returns false as soon as it finds a:not_safe
in the stream.This combo is (IMO) a bit cleaner and easier to understand than a single
Enum.reduce_while
that achieves the same "stateful short-circuiting check" logic.I use a boolean accumulator,
asc?
, to track whether the numbers are ascending (true
) or descending (false
). It starts out asnil
and gets set after the first interval is checked.I'm back with a Python solution!
Day 2 was a little trickier than day 1, but not horribly!
I did go a little over the top today to give it a command line interface, but it was a fun bit of practice. I also did it purely with vim, which was a fun departure from my normal vscode.
My partner is an excel whiz, and she's been playing around with them too. She's always been tempted to learn Python, but she's been a little intimidated with it so far.
solution
Ruby solution
Here are my Python solutions. I'm not doing them right at midnight this year, just when I have the time.
Part 1
Part 2
Well I was already up until almost midnight so I decided to rush solving day 2. And we all know rushing leads to lots of silly mistakes and terrible code. Somehow it was enough to get me on top of the Tildes leaderboard, although I'm sure I won't stay there.
Today's was almost as straightforward as yesterday's; just a lot of array iteration and manipulation which isn't terribly interesting to go through algorithmically. I wrote a naïve solution that "brute-forced" it, though at this stage that's more than sufficient for single-digit-millisecond runtimes (I think 4ms for part 2). My biggest hangup was making copies of arrays in C#; it's not as straightforward as it is in other languages (or maybe that was due to rushing).
Code — refactored. added some utility functions that made it (hopefully) very readable.