use std::collections::VecDeque; pub fn parse_snafus(input: &str) -> Vec<i64> { input.lines().map(snafu_to_num).collect() } pub fn snafu_to_num(snafu: &str) -> i64 { let mut pow = 1; let mut result = 0; for c in snafu.chars().rev() { let digit = match c { '=' => -2, '-' => -1, '0' => 0, '1' => 1, '2' => 2, _ => panic!("Unknown digit {}", c), }; result += pow * digit; pow *= 5; } result } pub fn num_to_snafu(num: i64) -> String { assert!(num > 0); let exp = (num as f64).log(5.0).floor() as u32 + 1; let mut result = VecDeque::with_capacity((exp as usize) + 1); let mut pow = 5_i64.pow(exp); let mut rem = num; while pow >= 1 { let digit = rem / pow; rem %= pow; result.push_back(digit); pow /= 5; } for i in (0..result.len()).rev() { if result[i] > 2 { result[i] -= 5; result[i - 1] += 1; } } result .iter() .skip_while(|d| **d == 0) .map(|d| match d { -2 => '=', -1 => '-', 0 => '0', 1 => '1', 2 => '2', _ => panic!("Unknown digit {}", d), }) .collect() } #[cfg(test)] mod tests { #[test] fn num_to_snafu_examples() { use crate::day25::num_to_snafu; assert_eq!(num_to_snafu(1), "1"); assert_eq!(num_to_snafu(2), "2"); assert_eq!(num_to_snafu(3), "1="); assert_eq!(num_to_snafu(4), "1-"); assert_eq!(num_to_snafu(5), "10"); assert_eq!(num_to_snafu(6), "11"); assert_eq!(num_to_snafu(7), "12"); assert_eq!(num_to_snafu(8), "2="); assert_eq!(num_to_snafu(9), "2-"); assert_eq!(num_to_snafu(10), "20"); assert_eq!(num_to_snafu(15), "1=0"); assert_eq!(num_to_snafu(20), "1-0"); assert_eq!(num_to_snafu(2022), "1=11-2"); assert_eq!(num_to_snafu(12345), "1-0---0"); assert_eq!(num_to_snafu(314159265), "1121-1110-1=0"); assert_eq!(num_to_snafu(4890), "2=-1=0"); } }