/// Number of trailing zeros tells us which bit is set and there should only be one set /// Do some math to convert to the needed priority fn bits_to_priority(b: u64) -> u32 { let trailing = b.trailing_zeros(); match trailing { 0..=25 => trailing + 27, 32..=57 => trailing - 31, _ => unreachable!(""), } } /// For each byte in the string offset it towards 0 /// to make it fit in u64 and set a bit at the position of its value fn to_bits(s: &str) -> u64 { s.bytes().fold(0, |a, v| a | 1 << (v - 65)) } pub fn part1(input: &str) -> impl std::fmt::Display { input .lines() .map(|l| l.split_at(l.len() / 2)) .map(|(l, r)| bits_to_priority(to_bits(l) & to_bits(r))) .sum::() } pub fn part2(input: &str) -> impl std::fmt::Display { let mut lines = input.lines(); let mut sum = 0; while let Some(l1) = lines.next() { let l2 = lines.next().expect("second is guaranteed to be there"); let l3 = lines.next().expect("third is guaranteed to be there"); sum += bits_to_priority(to_bits(l1) & to_bits(l2) & to_bits(l3)); } sum } #[test] fn test_part1() { assert_eq!("15", part1("A Y\nB X\nC Z").to_string()) } #[test] fn test_part2() { assert_eq!("12", part2("A Y\nB X\nC Z").to_string()) }