/ Rust / 2021 / 04.rs
04.rs
  1  #![feature(test)]
  2  
  3  use rustc_hash::FxHashSet;
  4  
  5  struct Input {
  6      nums: Vec<i32>,
  7      boards: Vec<Vec<Vec<i32>>>,
  8  }
  9  
 10  fn setup(input: &str) -> Input {
 11      let nums = input
 12          .lines()
 13          .next()
 14          .unwrap()
 15          .split(',')
 16          .map(|n| n.parse().unwrap())
 17          .collect();
 18      let boards = input
 19          .split("\n\n")
 20          .skip(1)
 21          .map(|board| {
 22              board
 23                  .lines()
 24                  .map(|line| {
 25                      line.split_whitespace()
 26                          .map(|n| n.parse().unwrap())
 27                          .collect()
 28                  })
 29                  .collect()
 30          })
 31          .collect();
 32      Input { nums, boards }
 33  }
 34  
 35  struct State {
 36      boards: Vec<Vec<Vec<i32>>>,
 37      marked: FxHashSet<i32>,
 38  }
 39  
 40  impl State {
 41      fn from_input(input: &Input) -> State {
 42          State {
 43              boards: input.boards.clone(),
 44              marked: FxHashSet::default(),
 45          }
 46      }
 47  
 48      fn mark(&mut self, num: i32) {
 49          self.marked.insert(num);
 50      }
 51  
 52      fn check_board(&self, board: usize) -> bool {
 53          let board = &self.boards[board];
 54          for row in board {
 55              if row.iter().all(|n| self.marked.contains(n)) {
 56                  return true;
 57              }
 58          }
 59          for i in 0..board[0].len() {
 60              if board.iter().all(|row| self.marked.contains(&row[i])) {
 61                  return true;
 62              }
 63          }
 64          false
 65      }
 66  
 67      fn get_score(&self, board: usize) -> i32 {
 68          self.boards[board]
 69              .iter()
 70              .flatten()
 71              .filter(|n| !self.marked.contains(n))
 72              .copied()
 73              .reduce(|a, b| a + b)
 74              .unwrap()
 75      }
 76  }
 77  
 78  fn part1(input: &Input) -> String {
 79      let mut state = State::from_input(input);
 80      for num in &input.nums {
 81          state.mark(*num);
 82          for i in 0..state.boards.len() {
 83              if state.check_board(i) {
 84                  return (num * state.get_score(i)).to_string();
 85              }
 86          }
 87      }
 88      panic!();
 89  }
 90  
 91  fn part2(input: &Input) -> String {
 92      let mut state = State::from_input(input);
 93      for num in &input.nums {
 94          state.mark(*num);
 95          let mut i = 0;
 96          while i < state.boards.len() {
 97              if !state.check_board(i) {
 98                  i += 1;
 99                  continue;
100              }
101              if state.boards.len() == 1 {
102                  return (num * state.get_score(i)).to_string();
103              }
104              state.boards.remove(i);
105          }
106      }
107      panic!()
108  }
109  
110  aoc::main!(2021, 4, ex: 1);