Advertisement
Guest User

Untitled

a guest
Dec 4th, 2021
337
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.19 KB | None | 0 0
  1. use anyhow::anyhow;
  2. use std::{collections::HashMap, str::FromStr};
  3.  
  4. use crate::util;
  5.  
  6. #[derive(Debug, Clone)]
  7. pub struct Board {
  8.     pub numbers: HashMap<(usize, usize), u64>,
  9.     pub marks: HashMap<(usize, usize), bool>,
  10. }
  11.  
  12. impl FromStr for Board {
  13.     type Err = anyhow::Error;
  14.  
  15.     fn from_str(s: &str) -> anyhow::Result<Self> {
  16.         let mut numbers = HashMap::new();
  17.         let mut marks = HashMap::new();
  18.  
  19.         for (y, line) in s.trim().lines().enumerate() {
  20.             for (x, n) in line.split_whitespace().enumerate() {
  21.                 numbers.insert((x, y), n.parse()?);
  22.                 marks.insert((x, y), false);
  23.             }
  24.         }
  25.  
  26.         Ok(Self { numbers, marks })
  27.     }
  28. }
  29.  
  30. impl Board {
  31.     fn mark(&mut self, number: u64) {
  32.         for (k, v) in &self.numbers {
  33.             if v == &number {
  34.                 // SAFETY: coords are identical in both hashmaps
  35.                 *self.marks.get_mut(k).unwrap() = true
  36.             }
  37.         }
  38.     }
  39.  
  40.     fn is_winner(&self) -> bool {
  41.         // check rows
  42.         for i in 0..5 {
  43.             let winner = self
  44.                 .marks
  45.                 .iter()
  46.                 // grab the x axis
  47.                 .filter(|((x, _), _)| x == &i)
  48.                 // if all booleans are true, this entire row has been marked
  49.                 .all(|((_, _), b)| *b);
  50.  
  51.             if winner {
  52.                 return true;
  53.             }
  54.         }
  55.  
  56.         // check columns
  57.         for j in 0..5 {
  58.             let winner = self
  59.                 .marks
  60.                 .iter()
  61.                 // grab the y axis
  62.                 .filter(|((_, y), _)| y == &j)
  63.                 // if all booleans are true, this entire column has been marked
  64.                 .all(|((_, _), b)| *b);
  65.  
  66.             if winner {
  67.                 return true;
  68.             }
  69.         }
  70.  
  71.         false
  72.     }
  73.  
  74.     fn get_unmarked(&self) -> Vec<u64> {
  75.         self.marks
  76.             .iter()
  77.             .filter_map(|((x, y), b)| {
  78.                 match b {
  79.                     // SAFETY: coords are identical in both hashmaps
  80.                     false => Some(*self.numbers.get(&(*x, *y)).unwrap()),
  81.                     true => None,
  82.                 }
  83.             })
  84.             .collect()
  85.     }
  86. }
  87.  
  88. pub fn get_input() -> anyhow::Result<(Vec<u64>, Vec<Board>)> {
  89.     let input = util::get_input(2021, 4)?;
  90.     let mut lines = input.lines();
  91.  
  92.     // get the numbers
  93.     let numbers = lines
  94.         .next()
  95.         .ok_or_else(|| anyhow!("couldn't get numbers"))?
  96.         .split(',')
  97.         .map(|n| Ok(n.parse()?))
  98.         .collect::<anyhow::Result<Vec<_>>>()?;
  99.  
  100.     // get the boards
  101.     let mut boards = Vec::new();
  102.     let mut board_iter = lines.peekable();
  103.  
  104.     while board_iter.peek().is_some() {
  105.         let board = board_iter
  106.             .by_ref()
  107.             .skip(1)
  108.             .take(5)
  109.             // reintroduce the \n so that we can parse it in it's original 5x5 format
  110.             .map(|l| l.to_owned() + "\n")
  111.             .collect::<String>()
  112.             .parse()?;
  113.  
  114.         boards.push(board);
  115.     }
  116.  
  117.     Ok((numbers, boards))
  118. }
  119.  
  120. pub fn part_one(numbers: &[u64], boards: &[Board]) -> Option<u64> {
  121.     // clone the boards
  122.     let mut boards = boards.to_vec();
  123.  
  124.     for number in numbers {
  125.         // apply number to each board, checking each board has/hasn't one
  126.         for board in boards.iter_mut() {
  127.             board.mark(*number);
  128.             if board.is_winner() {
  129.                 // calculate answer
  130.                 return Some(board.get_unmarked().iter().sum::<u64>() * number);
  131.             }
  132.         }
  133.     }
  134.  
  135.     None
  136. }
  137.  
  138. pub fn part_two(numbers: &[u64], boards: &[Board]) -> Option<u64> {
  139.     // clone the boards
  140.     let mut boards = boards.to_vec();
  141.     let mut boards_remaining = boards.len();
  142.  
  143.     for number in numbers {
  144.         for board in boards.iter_mut().peekable() {
  145.             board.mark(*number);
  146.  
  147.             if board.is_winner() && boards_remaining == 1 {
  148.                 // SAFETY: boards_remaining moves in lockstep with boards, we know there's one board left
  149.                 return Some(boards.first().unwrap().get_unmarked().iter().sum::<u64>() * number);
  150.             }
  151.         }
  152.  
  153.         // now filter out the winners
  154.         boards = boards
  155.             .iter()
  156.             .filter_map(|board| match board.is_winner() {
  157.                 false => Some(board.clone()),
  158.                 true => None,
  159.             })
  160.             .collect();
  161.  
  162.         boards_remaining = boards.len();
  163.     }
  164.  
  165.     None
  166. }
  167.  
  168. pub fn main() -> anyhow::Result<()> {
  169.     let (numbers, boards) = get_input()?;
  170.  
  171.     log::info!("d04p01: {}", part_one(&numbers, &boards).unwrap());
  172.     log::info!("d04p02: {}", part_two(&numbers, &boards).unwrap());
  173.  
  174.     Ok(())
  175. }
  176.  
  177. #[cfg(test)]
  178. mod tests {
  179.     #[test]
  180.     fn part_one() {
  181.         let (numbers, boards) = super::get_input().unwrap();
  182.         let result = super::part_one(&numbers, &boards).unwrap();
  183.         assert_eq!(result, 16_674);
  184.     }
  185.  
  186.     #[test]
  187.     fn part_two() {
  188.         let (numbers, boards) = super::get_input().unwrap();
  189.         let result = super::part_two(&numbers, &boards).unwrap();
  190.         assert_eq!(result, 7_075);
  191.     }
  192. }
  193.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement