use std::{ io::{stdin, Read}, ops::{BitAnd, BitOr}, }; fn item_priority(item: char) -> u32 { match item { 'a'..='z' => item as u32 - 'a' as u32 + 1, 'A'..='Z' => item as u32 - 'A' as u32 + 27, _ => panic!("invalid item {item}"), } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct ItemSet(u64); impl ItemSet { pub fn priority_of_single_item(self) -> Option { if self.0.is_power_of_two() { Some(self.0.trailing_zeros()) } else { None } } } impl FromIterator for ItemSet { fn from_iter>(iter: T) -> Self { Self( iter.into_iter() .map(item_priority) .fold(0, |acc, i| acc | (1 << i)), ) } } impl BitOr for ItemSet { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { Self(BitOr::bitor(self.0, rhs.0)) } } impl BitAnd for ItemSet { type Output = Self; fn bitand(self, rhs: Self) -> Self::Output { Self(BitAnd::bitand(self.0, rhs.0)) } } struct Rucksack { left: ItemSet, right: ItemSet, } fn main() { let mut data = String::new(); stdin().read_to_string(&mut data).unwrap(); let sacks: Vec<_> = data .lines() .map(|line| { let (left, right) = line.split_at(line.len() / 2); assert_eq!(left.len(), right.len()); let left = left.chars().collect(); let right = right.chars().collect(); Rucksack { left, right } }) .collect(); let sum1: u32 = sacks .iter() .map(|sack| (sack.left & sack.right).priority_of_single_item().unwrap()) .sum(); let sum2: u32 = sacks .chunks(3) .into_iter() .map(|sacks| { sacks .iter() .map(|sack| sack.left | sack.right) .reduce(BitAnd::bitand) .unwrap() .priority_of_single_item() .unwrap() }) .sum(); println!("{}", sum1); println!("{}", sum2); }