blob: de86470684413860718ecae66a12f6c0fcb3ecf2 (
plain)
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
|
use std::fmt;
use std::ops;
use std::cmp;
pub struct Snafu {
d: Vec<i8>
}
impl Snafu {
const DIGITS: [char; 5] = ['=', '-', '0', '1', '2'];
fn digit_to_i8(c: char) -> i8 {
for i in 0..5 {
if c == Snafu::DIGITS[i] { return i as i8 - 2; }
}
panic!("Invalid Snafu digit '{}'", c);
}
fn i8_to_digit(i: i8) -> char {
if i < -2 || i > 2 {
panic!("Invalid Snafu digit value {}", i);
}
Snafu::DIGITS[(i + 2) as usize]
}
pub fn ndigits(&self) -> usize {
self.d.len()
}
pub fn zero() -> Snafu {
Snafu { d: vec![0] }
}
pub fn from_str(s: &str) -> Snafu {
let mut d = vec![];
for c in s.chars() { d.push(Self::digit_to_i8(c)); }
d.reverse();
Snafu { d }
}
}
impl fmt::Display for Snafu {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Strip leading zeros
let mut n = self.ndigits()-1;
while self.d[n] == 0 { n -= 1; }
for i in (0..=n).rev() {
write!(f, "{}", Self::i8_to_digit(self.d[i]))?;
}
Ok(())
}
}
impl ops::AddAssign<&Snafu> for Snafu {
fn add_assign(&mut self, other: &Snafu) {
for i in 0..cmp::max(self.ndigits(), other.ndigits()) {
if i < other.ndigits() {
self.d[i] += other.d[i];
}
// Carry over, both ways
if i == self.ndigits()-1 { self.d.push(0); }
while self.d[i] > 2 { self.d[i+1] += 1; self.d[i] -= 5; }
while self.d[i] < -2 { self.d[i+1] -= 1; self.d[i] += 5; }
}
for i in 0..self.ndigits() {
if self.d[i] == 0 { self.d.pop(); } else { break; }
}
}
}
|