Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::fs::File;
- use std::io::{self, BufRead};
- use std::path::Path;
- #[derive(Debug)]
- pub struct BingoCell {
- pub selected: bool,
- pub number: u32,
- }
- #[derive(Debug)]
- pub struct BingoBoard {
- pub grid: Vec<Vec<BingoCell>>,
- }
- impl BingoBoard {
- /// Tick the number in a grid.
- ///
- /// # Arguments
- ///
- /// * `number` - The number that just been announced.
- pub fn tick_number(&mut self, number: u32) -> bool {
- for row in self.grid.iter_mut() {
- for cell in row.iter_mut() {
- if cell.number == number && !cell.selected {
- cell.selected = true;
- // Each number in a bingo grid are unique...
- return true;
- }
- }
- }
- false
- }
- /// Test if the grid is a winning one or not.
- ///
- /// # Arguments
- pub fn is_winner(&self) -> bool {
- // Avoid a crash
- if self.grid.is_empty() {
- return false;
- }
- // We do both per row and per column at the same time...
- let column_len: usize = self.grid[0].len();
- let mut column_count: Vec<usize> = vec![0; column_len];
- let mut row_count: usize;
- for row in self.grid.iter() {
- row_count = 0;
- for (i, cell) in row.iter().enumerate() {
- if cell.selected {
- row_count += 1;
- column_count[i] += 1;
- if column_count[i] == column_len || row_count == row.len() {
- return true;
- }
- }
- }
- }
- false
- }
- /// Get the final board value (sum of cells "non-selected".
- ///
- /// # Arguments
- pub fn board_value(&self) -> u32 {
- self.grid.iter().map(|row| {
- row.iter().filter_map(|cell| {
- match cell.selected {
- true => None,
- false => Some(cell.number)
- }
- }).sum::<u32>()
- }).sum::<u32>()
- }
- }
- fn aoc04_part1(draw: &Vec<u32>, boards: &mut Vec<BingoBoard>) -> u32 {
- for number in draw {
- // Adding the number to each board
- for board in boards.iter_mut() {
- if board.tick_number(*number) && board.is_winner() {
- return number * board.board_value();
- }
- }
- }
- 0
- }
- fn aoc04_part2(draw: &Vec<u32>, boards: &mut Vec<BingoBoard>) -> u32 {
- for number in draw {
- // Adding the number to each board
- boards.iter_mut().for_each(|board| { board.tick_number(*number); });
- if boards.len() == 1 && boards[0].is_winner() {
- return number * boards[0].board_value();
- }
- // THE RETAINNNNNN
- boards.retain(|c| !c.is_winner());
- }
- 0
- }
- fn main() {
- let mut draw: Vec<u32> = Vec::new();
- let mut boards: Vec<BingoBoard> = Vec::new();
- let mut reset: bool = false;
- let mut grid: Vec<Vec<BingoCell>> = Vec::new();
- if let Ok(lines) = read_lines("./input.txt") {
- // Consumes the iterator, returns an (Optional) String
- for line in lines.into_iter().flatten() {
- // First line is the draw numbers...
- if draw.len() == 0 && !line.is_empty() {
- draw = line.split(',').filter_map(|c| c.parse::<u32>().ok()).collect::<Vec<u32>>()
- }
- // Others are the bingo grids...
- if reset {
- if !grid.is_empty() {
- boards.push(BingoBoard { grid });
- }
- grid = Vec::new();
- reset = false;
- }
- if line.is_empty() {
- reset = true;
- } else {
- let cells: Vec<BingoCell> = line.split(' ').filter_map(|c| c.parse::<u32>().ok()).map(|number| BingoCell {
- selected: false,
- number
- }).collect::<Vec<BingoCell>>();
- if !cells.is_empty() {
- grid.push(cells);
- }
- }
- }
- }
- // Pushing the last one if any
- if !grid.is_empty() {
- boards.push(BingoBoard {
- grid
- });
- }
- let result = aoc04_part1(&draw, &mut boards);
- println!("Winner {}", result);
- let result = aoc04_part2(&draw, &mut boards);
- println!("Last Winner {}", result);
- }
- // The output is wrapped in a Result to allow matching on errors
- // Returns an Iterator to the Reader of the lines of the file.
- fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> where P: AsRef<Path>, {
- let file = File::open(filename)?;
- Ok(io::BufReader::new(file).lines())
- }
Add Comment
Please, Sign In to add comment