I've been doing Everybody Codes,
a set of programming challenges in the style of Advent of
Code, now in its second year.
I'll refer throughout to parts A, B and C, as that's the easiest
way for me to keep a consistent system.
All of my code is on Codeberg
Day 1
Fairly straightforward. Probably would have been easier if I hadn't
been hand-coding a parser as I went along (moving from part 1 to 2
involved two digits): memo to future Roger, just use Winnow, eh?
Feeling rusty, no pun intendded.
Day 2
Apparently I used mostly regex parsing last year. Anyway, loading
winnow back into my head feels too much like hard work right now.
I got away with assuming that Rust's integer division would round
towards zero.
Clearly a case for a custom struct, then impl functions for the
maths.
All right, I thought the maths looked vaguely familiar, but then the
diagram in the notes for part 2 made it obvious.
And a nice easy part 3 that just required me to remove the .step_by
(and run in release mode).
Day 3
I thought this one would be harder than it was, since I never had to
search actual combinations.
A: the set with the highest value will be the set that includes each
crate size once. So deduplicate the Vec of crate sizes (I turn it
into a HashSet because I like sets) and add it up.
B: the set of N with the lowest value will be the lowest N distinct
values. Sort, dedup, slice.
C: the number of distinct sets is the largest number of instances of a
single value. So I throw this at a Counter class (I seem to do a lot
of things that can be resolved with one of these), and return the
maximum cardinality.
Day 4
Basically it's "prevent overflows" (and I'm happy to see that even
using Rust's built-in 128-bit integer type isn't enough to do this on
its own). My solution is to keep an ongoing total of numerator and
denominator, and after each change divide them by their gcd (or hcf as
I did it at school). I already had code to do that, so I didn't go
looking for a library (looks as though num::integer would be the
right answer).
Part B does the same thing in reverse, but needs a fudge factor for
non-integer results.
Part C splits the train into pairs.
Day 5
I was expecting to do more with the structure, but expectations are a
mocker in these things and premature optimisation is a waste of time.
I assume that no value in the sword definition can be zero. This turns
out to be correct for my examples. Should probably have used
Options.
Part A is getting used to the structure (I initially thought that only
the current level was relevant).
Part B brings that calculation inside the parse loop, and we snag
minimum and maximum values. (Prepature optimisation here as I parsed
the index value.)
Part C seemed fiddly until I realised that I'd do best to implement a
custom structure with its own sorting rules. (And Rust can already
sort a list of Vec based on their contents, which makes my life much
easier.)