Skip to content

Advent of Code Day Three - Rucksack Reorganization

December 4, 2022 | 12:26 PM

Rucksack Reorganization

In Day 3 we learn that there is a method to the madness of the elves organization of their rucksacks. The rucksacks have 2 compartments and we are gauranteed that the two portions are equal (halves).

Part 1

Our puzzle input is 300 lines of characters where each line represents and rucksack that must be inspected.

As is commonplace now, I created the input file and read that data in.

fn main() {
    let input: &str = include_str!("./day3_input.txt");

    let lines = input.split('\n');

/* ... */
}

I then decided to ge the low hanging fruit first by writing the method that will get the points for a given character.

fn points_from_char(c: char) -> i32 {
    let c_point = c as i8;
    if c.is_lowercase() {
        return (c_point - 96) as i32;
    }
    return (c_point - 38) as i32;
}

Now I needed a method to test that any character from the first string is present inside the 2nd half of the string.
Looking back, I could/should refactor this, which will be a different post since I am so far behind.

fn get_duplicate_char(test_char: &char, string_half: &str) -> i32 {
    for c in string_half.char_indices() {
        if c.1.eq(test_char) {
            return points_from_char(c.1);
        }
    }
    return 0;
 }

Finally, I can start the main method.
I created a total varible to keep the aggregated total of points. I then iterated over each line, splitting it in half, and then calling my get_duplicate_char method for each character in the first half. Then I printed the grand total.

fn main() {
    let input = include_str!("./day3.input.txt");
    let lines = input.split('\n');
    let mut total = 0;

    for line in lines {
        let count = line.chars().count();

        let first_half = &line[..count/2].chars().into_iter();
        let last_half = &line[count/2 .. count];


        for c in line[..count/2].chars() {
            let dup_points = get_duplicate_char(&c, last_half);
            if dup_points > 0 {
                total += dup_points;
                println!("Dup Points: {:?} Char: {:?}, Char as int {:?}", dup_points, c, c as i8);
                break;
            }
        }

    }

    println!("TOTAL: {:?}", total);
}

Part 2

For part 2 we find that the elves are in groups of 3 and they need to keep the rucksacks for their group. This can be indicated by the common character that appears in all three rucksacks.

We get to reuse the points_from_char method from part 1.

fn points_from_char(c: char) -> i32 {
    let c_point = c as i8;
    if c.is_lowercase() {
        return (c_point - 96) as i32;
    }
    return (c_point - 38) as i32;
}

Now we need to find the common character across the different lines. I started with the method that evaluates the strings.

fn find_common_char(c1: &str, c2: &str, c3: &str) -> i32 {
    for c in c1.chars() {
        if c2.contains(c) && c3.contains(c) {
            return points_from_char(c);
        }
    }
    return 0;
}

I next used the peekable() method to get 3 lines at a time and afford a bit of protection from index-out-of-bounds errors.

Final Solution

Here is the whole file after I was done:

fn main() {
    let input = include_str!("./day3.input.txt");
    let lines= input.split('\n');
    let mut total = 0;

    let mut x = lines.peekable();
    while x.peek().is_some() {
        let grp: Vec<&str> = x.by_ref().take(3).collect();
        if grp.len() < 3 {
            println!("{:?}", total);
            return;
        }
        total += find_common_char(grp[0], grp[1], grp[2]);
    }
}

fn find_common_char(c1: &str, c2: &str, c3: &str) -> i32 {
    for c in c1.chars() {
        if c2.contains(c) && c3.contains(c) {
            return points_from_char(c);
        }
    }
    return 0;
}
fn points_from_char(c: char) -> i32 {
    let c_point = c as i8;
    if c.is_lowercase() {
        return (c_point - 96) as i32;
    }
    return (c_point - 38) as i32;
}