/ Rust / 2021 / 08.rs
08.rs
  1  #![feature(test)]
  2  
  3  use rustc_hash::{FxHashMap, FxHashSet};
  4  
  5  struct Line {
  6      patterns: Vec<String>,
  7      output: Vec<String>,
  8  }
  9  
 10  type Input = Vec<Line>;
 11  
 12  fn setup(input: &str) -> Input {
 13      input
 14          .lines()
 15          .map(|line| {
 16              let mut line = line.trim().split(" | ");
 17              let mut parse = || {
 18                  line.next()
 19                      .unwrap()
 20                      .split(' ')
 21                      .map(|x| x.to_string())
 22                      .collect()
 23              };
 24              Line {
 25                  patterns: parse(),
 26                  output: parse(),
 27              }
 28          })
 29          .collect()
 30  }
 31  
 32  fn part1(input: &Input) -> String {
 33      input
 34          .iter()
 35          .map(|line| {
 36              line.output
 37                  .iter()
 38                  .filter(|x| [2, 3, 4, 7].contains(&x.len()))
 39                  .count()
 40          })
 41          .sum::<usize>()
 42          .to_string()
 43  }
 44  
 45  fn parse_num(num: &str) -> u16 {
 46      num.chars()
 47          .map(|c| 1 << ((c as u16) - ('a' as u16)))
 48          .sum::<u16>()
 49  }
 50  
 51  fn is_subset(mut a: u16, mut b: u16) -> bool {
 52      while a > 0 {
 53          if 1 & a & !b == 1 {
 54              return false;
 55          }
 56          a >>= 1;
 57          b >>= 1;
 58      }
 59      true
 60  }
 61  
 62  fn part2(input: &Input) -> String {
 63      let digits = FxHashMap::from_iter([
 64          ((7, 2), 1),
 65          ((2, 5), 2),
 66          ((3, 5), 3),
 67          ((3, 4), 4),
 68          ((4, 5), 5),
 69          ((5, 3), 7),
 70          ((1, 7), 8),
 71      ]);
 72  
 73      input
 74          .iter()
 75          .map(|line| {
 76              let patterns: Vec<u16> = line.patterns.iter().map(|s| parse_num(s)).collect();
 77              let output: Vec<u16> = line.output.iter().map(|s| parse_num(s)).collect();
 78              let mut mp: FxHashMap<u16, u8> = FxHashMap::default();
 79              let mut rp: FxHashMap<u8, u16> = FxHashMap::default();
 80              let mut u: FxHashSet<u16> = FxHashSet::from_iter(patterns.iter().cloned());
 81              for x in &patterns {
 82                  let sc = patterns.iter().filter(|y| is_subset(*x, **y)).count();
 83                  match digits.get(&(sc, x.count_ones())) {
 84                      None => {}
 85                      Some(digit) => {
 86                          mp.insert(*x, *digit);
 87                          rp.insert(*digit, *x);
 88                          u.remove(x);
 89                      }
 90                  }
 91              }
 92  
 93              let x = *u
 94                  .iter()
 95                  .find(|x| !is_subset(*rp.get(&5).unwrap(), **x))
 96                  .unwrap();
 97              mp.insert(x, 0);
 98              u.remove(&x);
 99  
100              let x = *u
101                  .iter()
102                  .find(|x| is_subset(*rp.get(&4).unwrap(), **x))
103                  .unwrap();
104              mp.insert(x, 9);
105              u.remove(&x);
106  
107              let x = *u.iter().next().unwrap();
108              mp.insert(x, 6);
109  
110              output
111                  .iter()
112                  .map(|x| *mp.get(x).unwrap() as u32)
113                  .reduce(|a, b| a * 10 + b)
114                  .unwrap()
115          })
116          .sum::<u32>()
117          .to_string()
118  }
119  
120  aoc::main!(2021, 8, ex: 1[b], 2);