1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
fn from_snafu(s: &str) -> i64 {
// This is the easy bit...
let mut i: i64 = 0;
let mut pow: i64 = 1;
for ch in s.chars().rev() {
match ch {
'2' => i += 2 * pow,
'1' => i += 1 * pow,
'0' => {}, // additive identity!
'-' => i += -1 * pow,
'=' => i += -2 * pow,
_ => panic!("unexpected input {}", ch)
}
pow *= 5;
}
i
}
fn to_snafu(mut i: i64) -> String {
// how to do this :thinking: add two, mod 5,take away 2? // nope
let mut res = Vec::<char>::new();
while i != 0 {
let d = ((i + 2) % 5) - 2;
let ch = match d {
2 => '2',
1 => '1',
0 => '0',
-1 => '-',
-2 => '=',
_ => panic!("unexpected digit {}", d)
};
res.push(ch);
i = (i + 2) / 5;
}
res.reverse();
res.into_iter().collect::<String>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_snafu() {
let cases = vec![
("1=-0-2", "1747"),
( "12111", "906"),
( "2=0=", "198"),
( "21", "11"), // works
( "2=01", "201"), // 201,1 > 40,0 > 8,= > 1,1
( "111", "31"), // works
( "20012", "1257"), //works
( "112", "32"), // works
( "1=-1=", "353"), // broke
( "1-12", "107"),
( "12", "7"),
( "1=", "3"),
( "122", "37"),
];
for (snafu, decimal) in cases {
let x = from_snafu(snafu);
assert_eq!(x.to_string().as_str(), decimal);
assert_eq!(to_snafu(x), snafu);
}
}
}
pub fn run(input: String) {
let s: i64 = input.lines()
.map(from_snafu)
.sum();
println!("Day 25: {}", to_snafu(s));
}
|