84 lines
2.1 KiB
Rust
84 lines
2.1 KiB
Rust
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");
|
|
}
|
|
}
|