/ Rust / 2021 / 03.rs
03.rs
 1  #![feature(test, extract_if)]
 2  
 3  type Input = Vec<String>;
 4  
 5  fn setup(input: &str) -> Input {
 6      input.lines().map(|s| s.to_string()).collect()
 7  }
 8  
 9  fn count(input: &Input, i: usize, chr: &char) -> usize {
10      input
11          .iter()
12          .filter(|s| s.chars().nth(i).unwrap() == *chr)
13          .count()
14  }
15  
16  fn most_common(input: &Input, i: usize) -> char {
17      "01".chars().max_by_key(|c| count(input, i, c)).unwrap()
18  }
19  
20  fn least_common(input: &Input, i: usize) -> char {
21      "01".chars().min_by_key(|c| count(input, i, c)).unwrap()
22  }
23  
24  fn part1(input: &Input) -> String {
25      let mut most = 0;
26      let mut least = 0;
27      for i in 0..input[0].len() {
28          most = most << 1 | (most_common(input, i) as u32 - '0' as u32);
29          least = least << 1 | (least_common(input, i) as u32 - '0' as u32);
30      }
31      (most * least).to_string()
32  }
33  
34  fn find(input: &Input, x: bool) -> isize {
35      let mut out = input.clone();
36      for i in 0..input[0].len() {
37          let mx = if x {
38              least_common(&out, i)
39          } else {
40              most_common(&out, i)
41          };
42          out.extract_if(|x| x.chars().nth(i).unwrap() != mx).count();
43          if out.len() == 1 {
44              return isize::from_str_radix(out[0].as_str(), 2).unwrap();
45          }
46      }
47      panic!();
48  }
49  
50  fn part2(input: &Input) -> String {
51      (find(input, true) * find(input, false)).to_string()
52  }
53  
54  aoc::main!(2021, 3, ex: 1);