Nice to get back into it!
A funny thing to note in day_01_v2
: I thought that using match direction {}
inside the for _i in 1..=steps {}
loop would prove costly, but doing it outside the loop to store which part of position
to modify and by how much, ends up being slower.
I must admit: the biggest pleasure in learning a new language is when it compiles right on your first time.
Iterators can be a special kind of hell in Rust, especially when combined, and each type specializes itself further, but in the end, they work.
Jumping around between char
, u8
, and i32
is a bit of a pain, but it's not too hard once you get it.
Interestingly, when calculating the checksum, it is FASTER to reiterate over the string for each new character we find, rather than query the index straight from a HashMap.
Hey look, it's those pesky MD5 hashes again!
For efficiency purposes, the MD5 crate that I am using is returning hashes in their hexadecimal value, so when humans are expecting to get 32 characters, the digest is returned as 16 u8
values (reminder, an u8
goes from 0
to 255
so it can store 2 (* 16 = 256)
hexadecimal values). It's a bit of a mental gymnastic to juggle with afterwards, but it's not impossible either.
Playing with specific types for closures can be a pain, but it's often very funny to understand how things work under the hood.
Some iterators are annoying, but sometimes, like when calculating whether there is an intersection of two sets, it's great to not generate the whole intersection and just peek at the first element.
I wouldn't call it an "object model", but I like the way Rust works with impl X for Y
.
Also, remember the splice()
method, it's very useful to replace large parts of a vector at once.
I knew the Rust version would be faster than my Ruby implementation, but I still felt I wasn't fast enough. I compared myself to galenelias's implementation and indeed I wasn't fast enough.
I went back to the workbench to try another implementation, and to my delight, I was the faster. But still not faster than fornwall's implementation.
Looking at it carefully proved very smart: both galenelias and me lost too much time creating a string, then getting its length, when the exercise only asked to get the string's length.
This exercise got me to face the worst part of Rust: iterating over a hash map while mutating it.
Ugh. I hated this just as much as the first time.
Finally, we are back into interesting exercises!
...
Computing MD5 hashes is never interesting.
Finally, something funny to do.
For once, I'm faster than my rustaceans counterparts. In that case, manipulating Vec<bool>
instead of String
worked better.
Another thing of note is that if you know how to optimize your loop-down, you can win a lot of time.
A big part of this day was bout building a BreadthFirstSearch library that would be flexible enough to reuse in other exercises, since there are SO MANY in this year.
There was some confusion between all the generics, abstractions, and types, especially since this day got some strange rules (storing together position+path) but in the end, I think I got it, and implementing it on day 13 (which only got a position) was really fast, and execution time got faster too.
Easy come, easy go.
As easy in Rust as it was in Ruby.
One of Rust's biggest pleasure is code that compiles on the first try.
I love interpreters.
So far, my BreadthFirstSearch library has saved me from rewriting a BFS from scratch twice.
I had forgotten the original was taking ten minutes to run. This one takes only seven seconds, and I'll be happy with it.
Look, BreadthFirstSearch library is coming to our rescue again!
The Assembunny library proved very useful too \o/