Advent of Code 2024, Day 1

I am doing Advent of Code 2024 in Rust! This is day 1, chronicles on learnings and solutions.

Photo of colourful terraced houses that look very similar to each other.
Photo by Ross Joyner on Unsplash

Part of the AoC 2024 series

New year, new me, new Advent of Code! This year Iā€™m using Rust to solve these, because I now have enough handle on Golang that the weakest link is the knowledge, or rather lack thereof, of advanced data manipulation algorithms rather than the language itself.

Rust however, Iā€™m not so great at, so AoC is my way of getting my katas in.

This is going to be a series of blog posts, this one being the one, and whichever I get stuck on is going to be the last in the series. They will all be linked in some fancypants dropdown list someplace. I havenā€™t figured that part out yet.

As usual, spoilers be here, as Iā€™m going to write about the solutions, and the challenges I faced.

Oh, links, if you want to follow along:

GitHub - javorszky/adventofcode2024
Contribute to javorszky/adventofcode2024 development by creating an account on GitHub.
Advent of Code 2024

Day 1

All right, this is basically parsing a file into two different lists, sorting them, and then comparing them side by side.

Reading the file was fairly easy, I didnā€™t get stuck on it much, besides not really being 100% sure if I use a workspace, what fs::read_to_string() is going to consider the ā€œcurrentā€ directory, from which we need ito be relative to where the file is. Turns out itā€™s relative to the project root, rather than the workspace member root.

The second hurdle was figuring out this piece of code:

let boo: Vec<i32> = trimmed
    .split("\n")
    .flat_map(|line: &str| -> Vec<i32> {
        line.split("   ")
            .map(|x: &str| -> i32 { x.parse::<i32>().unwrap_or(i32::MAX) })
            .collect::<Vec<i32>>()
    })
    .collect();

trimmed is the entire file with the trailing newline removed. The amount of ā€œyou have to specify the type in the closure!!ā€ and collect and iter and into_iter issues Iā€™ve run into is huge. I still kind of donā€™t understand how and why flat_map works, but Iā€™m going to trust the process and the later days.

Break the file contents by newline, then for each line break it by three spaces, then for those parts try to convert them to i32 sizes, return the (2 long) vector of the two numbers, and then flatten the vector of vectors.

And then iterate over it, and put the numbers left and right based on the index being divisible by 2, and then sort them.

let mut left_list: Vec<i32> = Vec::new();
let mut right_list: Vec<i32> = Vec::new();
for (i, x) in boo.into_iter().enumerate() {
    if i % 2 == 0 {
        left_list.push(x);
    } else {
        right_list.push(x);
    }
}

left_list.sort();
right_list.sort();

But I canā€™t sort them in place, or rather I canā€™t use the .sort() method when Iā€™m also assigning them to a struct, because ugh. So this wonā€™t work:

Day01 {
    list_left: left_list.sort(),
    list_right: right_list.sort(),
}

I just want to assign or move the sorted lists. No, the expected type of Vec<i32> , what list_left and list_right are, arenā€™t of type (). Super helpful. No, I have to sort them first, and then assign them, like I do in the source code.

Actually summing differences is rather trivial.

Part 2

This introduces a hashmap. This thing: https://doc.rust-lang.org/std/collections/struct.HashMap.html. Super easy. Iā€™m also using RustRover as my IDE, and that has code intelligence based on local code, so when I wrote a for loop for my right list, and I started with map, it being a hashmap, it knew that I probably want to create a frequency table, and autocompleted the rest of the line for me:

for x in self.list_right.iter() {
    map.entry(x).and_modify(|e| *e += 1).or_insert(1);
}

Am I cheating with this? I donā€™t feel like I am, because itā€™s not doing anything I donā€™t understand, but it did help me figure out that I have the .entry method, and the .and_modify method, and the .or_insert method. All of which are on the intro to hash maps page as above.

The remaining issue was me being dumb and not reading the exercise correctly, and summing the wrong thing.

Two ā­ļøā­ļø later, itā€™s time to go to sleep.

Until tomorrow, friends!