/** Solution for Advent of Code 2022 day 3. * https://adventofcode.com/2022/day/3 */ use aoc2022::StdError; 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 part1: u32 = lines .iter() .map(|l| { assert!(l.len() % 2 == 0); // We won't be able to evenly split a odd-length line! let (one, two) = (&l[0..l.len() / 2], &l[l.len() / 2..]); // Make sets out of the characters in each compartment... HashSet::::from_iter(one.chars()) // ... then calculate the intersection, giving us the "items" (chars) in common .intersection(&HashSet::from_iter(two.chars())) .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: {}", 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(()) }