diff --git a/src/bin/day3.rs b/src/bin/day3.rs index 810c108..465f0e6 100644 --- a/src/bin/day3.rs +++ b/src/bin/day3.rs @@ -6,13 +6,24 @@ use std::collections::HashSet; use std::fs::File; use std::io::{BufRead, BufReader}; +// Map a character (indicating an "item") to its "priority". +fn char_to_prio(c: char) -> u32 { + // Fortunately we can cast all chars to u32, which makes this a matter of some simple + // arithmetic. + match c { + 'a'..='z' => c as u32 - 'a' as u32 + 1, + 'A'..='Z' => c as u32 - 'A' as u32 + 27, + _ => panic!("Got non-ascii alphabetic char!"), + } +} + fn main() -> StdError<()> { // Open the input file and split all the lines. let lines: Vec<_> = BufReader::new(File::open("input/day3.txt")?) .lines() .collect::>()?; // "Short circuit" any Errors in the iterator - let sum: u32 = lines + let part1: u32 = lines .iter() .map(|l| { assert!(l.len() % 2 == 0); // We won't be able to evenly split a odd-length line! @@ -22,17 +33,35 @@ fn main() -> StdError<()> { HashSet::::from_iter(one.chars()) // ... then calculate the intersection, giving us the "items" (chars) in common .intersection(&HashSet::from_iter(two.chars())) - .map(|c| match c { - // Now, we map our "items" to their "priorities". - // Fortunately we can cast all chars to u32, which makes this a matter of some - // simple arithmetic. - 'a'..='z' => (*c as u32) - 'a' as u32 + 1, - 'A'..='Z' => (*c as u32) - 'A' as u32 + 27, - _ => panic!("Got non-ascii alphabetic char!"), - }) + .map(|c| char_to_prio(*c)) .sum::() // Sum the priorities of items in common in each "rucksack" }) .sum(); // Sum all the rucksacks' priorities - println!("Part 1: {}", sum); + println!("Part 1: {}", part1); + + let part2: u32 = lines + // First, map our lines to hashsets of their chars + .iter() + .map(|l| HashSet::from_iter(l.chars())) + .collect::>() + // Then split them into chunks of 3 + .chunks(3) + .map(|c: &[HashSet<_>]| { + // And reduce each chunk of 3 into a single intersection of chars... + let common: Vec = c + .into_iter() + .cloned() + .reduce(|acc, s| acc.intersection(&s).cloned().collect()) + .unwrap() + .into_iter() + .collect(); + // ... which should only be one! + assert!(common.len() == 1); + common[0] + }) + .map(char_to_prio) + .sum(); + println!("Part 2: {}", part2); + Ok(()) }