Advent of Rust // Day 3

I was surprised there’s no built-in way to find the intersection of multiple sets. I started to implement a function for this, but quickly discarded it in favor of a more specific one for the task at hand. After all, there’s exactly one character to find for each bunch of strings.

fn first_intersecting_character(strings: Vec<&str>) -> char {  
    'next_char: for c in strings[0].chars() {  
        for s in strings[1..].iter() {  
            if !s.contains(c) {  
                continue 'next_char;  
            }  
        }  
  
        return c;  
    }  
  
    panic!("No intersecting character found");  
}

Converting chars to priorites was pretty straightforward once I learned that you can simply cast a char to an int. I also learned that there’s no ternary, but you can use if conditions inline.

fn priority_sum(items: Vec<char>) -> u32 {  
    return items.iter()  
        .map(|c| (*c as u32) - if c.is_uppercase() { 38 } else { 96 })  
        .sum();  
}

Plugging it all together was easy. Part one: priority sum of the intersecting character of the left and right half of each line. I wish there was a way to convert a tuple to a vector inline, though.

fn part_one(input: Vec<&str>) -> u32 {  
    return priority_sum(  
        input.iter()  
            .map(|line| {  
                let (a, b) = line.split_at(line.len() / 2);  
                return first_intersecting_character(vec![a, b]);  
            })  
            .collect()  
    );  
}  

Part two: Priority sum of the intersecting character of every chunk of three lines:

fn part_two(input: Vec<&str>) -> u32 {  
    return priority_sum(  
        input.chunks(3)  
            .map(|lines| first_intersecting_character(lines.to_vec()))  
            .collect()  
    );  
}

I also had a look at how tests work in Rust today. As someone who recently addressed his liking for Colocating Tests and Production Code, I enjoyed putting them right into the same file. Not sure if I’m a fan of assertion arguments named left and right instead of expected and actual.

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn first_intersecting_character_should_return_only_the_first_if_there_are_multiple_intersections() {
        let result = first_intersecting_character(vec!["abcd", "bcde", "cdef"]);

        assert_eq!('c', result);
    }

    #[test]
    #[should_panic]
    fn first_intersecting_character_should_panic_if_there_is_no_intersecting_character() {
        first_intersecting_character(vec!["abc", "def", "ghi"]);
    }

    #[test]
    fn part_one_example() {
        let result = part_one(vec![
            "vJrwpWtwJgWrhcsFMMfFFhFp",
            "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL",
            "PmmdzqPrVvPwwTWBwg",
            "wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn",
            "ttgJtRGJQctTZtZT",
            "CrZsJsPPZsGzwwsLwLmpwMDw",
        ]);

        assert_eq!(157, result);
    }

    #[test]
    fn part_two_example() {
        let result = part_two(vec![
            "vJrwpWtwJgWrhcsFMMfFFhFp",
            "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL",
            "PmmdzqPrVvPwwTWBwg",
            "wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn",
            "ttgJtRGJQctTZtZT",
            "CrZsJsPPZsGzwwsLwLmpwMDw",
        ]);

        assert_eq!(70, result);
    }
}

The full source and solutions for the others puzzles of Advent of Code can be found in my GitHub repository.

See also in Advent of Rust

Comments

You can leave a comment by replying to this post on Mastodon.