aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

common.rs (1758B)


      1 use std::fmt;
      2 use std::ops;
      3 use std::cmp;
      4 
      5 pub struct Snafu {
      6     d: Vec<i8>
      7 }
      8 
      9 impl Snafu {
     10     const DIGITS: [char; 5] = ['=', '-', '0', '1', '2'];
     11 
     12     fn digit_to_i8(c: char) -> i8 {
     13         for i in 0..5 {
     14             if c == Snafu::DIGITS[i] { return i as i8 - 2; }
     15         }
     16         panic!("Invalid Snafu digit '{}'", c);
     17     }
     18 
     19     fn i8_to_digit(i: i8) -> char {
     20         if i < -2 || i > 2 {
     21             panic!("Invalid Snafu digit value {}", i);
     22         }
     23         Snafu::DIGITS[(i + 2) as usize]
     24     }
     25 
     26     pub fn ndigits(&self) -> usize {
     27         self.d.len()
     28     }
     29 
     30     pub fn zero() -> Snafu {
     31         Snafu { d: vec![0] }
     32     }
     33 
     34     pub fn from_str(s: &str) -> Snafu {
     35         let mut d = vec![];
     36         for c in s.chars() { d.push(Self::digit_to_i8(c)); }
     37         d.reverse();
     38         Snafu { d }
     39     }
     40 }
     41 
     42 impl fmt::Display for Snafu {
     43     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     44         // Strip leading zeros
     45         let mut n = self.ndigits()-1;
     46         while self.d[n] == 0 { n -= 1; }
     47 
     48         for i in (0..=n).rev() {
     49             write!(f, "{}", Self::i8_to_digit(self.d[i]))?;
     50         }
     51         Ok(())
     52     }
     53 }
     54 
     55 impl ops::AddAssign<&Snafu> for Snafu {
     56     fn add_assign(&mut self, other: &Snafu) {
     57         for i in 0..cmp::max(self.ndigits(), other.ndigits()) {
     58             if i < other.ndigits() {
     59                 self.d[i] += other.d[i];
     60             }
     61 
     62             // Carry over, both ways
     63             if i == self.ndigits()-1 { self.d.push(0); }
     64             while self.d[i] > 2  { self.d[i+1] += 1; self.d[i] -= 5; }
     65             while self.d[i] < -2 { self.d[i+1] -= 1; self.d[i] += 5; }
     66         }
     67 
     68         for i in 0..self.ndigits() {
     69             if self.d[i] == 0 { self.d.pop(); } else { break; }
     70         }
     71     }
     72 }