From 64e22194d39d2914db1e3bf93c90de9e0791d9b3 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Fri, 1 Dec 2023 09:21:16 +0100 Subject: chore: reorganize project structure --- 2021/day04/src/main.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 2021/day04/src/main.rs (limited to '2021/day04/src/main.rs') diff --git a/2021/day04/src/main.rs b/2021/day04/src/main.rs new file mode 100644 index 0000000..fd74866 --- /dev/null +++ b/2021/day04/src/main.rs @@ -0,0 +1,147 @@ +use std::fs; +use std::fmt; +use std::path::Path; + +struct Bingo { + cards: Vec +} + +impl Bingo { + fn update(&mut self, draw: u32) -> Vec<(usize,u32)> { + self.cards.iter_mut().enumerate().filter_map( + |(i,c)| { + if let Some(s) = c.mark(draw) { + if c.ingame { return Some((i,s)) } + } + None + } + ).collect() + } + + fn simulate(&mut self, draws: &[u32]) -> u32 { + if draws.len() > 0 { + if let Some((_,score)) = self.update(draws[0]).first() { + *score + } else { + self.simulate(&draws[1..]) + } + } else { + unreachable!() + } + } + + fn simulate_all(&mut self, draws: &[u32]) -> u32 { + if draws.len() > 0 { + for (index,score) in self.update(draws[0]) { + if self.cards.iter().filter(|c| c.ingame).count() == 1 { + return score + } + self.cards[index].ingame = false; + } + self.simulate_all(&draws[1..]) + } else { + unreachable!() + } + } +} + +#[derive(Clone)] +struct BingoCard { + ingame: bool, + nums: Vec<(u32,bool)> +} + +impl BingoCard { + fn mark(&mut self, n: u32) -> Option { + if let Some(pos) = self.nums.iter().position(|c| c.0 == n) { + self.nums[pos].1 = true; + if self.check(pos) { + Some(self.score() * n) + } else { None } + } else { None } + } + + fn check(&self, pos: usize) -> bool { + let row = pos / 5; + let col = pos % 5; + (5*row..5*row+5).all(|c| self.nums[c].1) + || (0usize..5).all(|c| self.nums[c*5+col].1) + } + + fn score(&self) -> u32 { + self.nums.iter().filter_map(|c| if c.1 { None } else { Some(c.0) }).sum() + } +} + +impl fmt::Display for BingoCard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = self.nums.iter().enumerate().map( + |(n,c)| format!("{:>2}{}{}", c.0, if c.1 { '*' } else { ' ' }, if (n+1)%5 == 0 { '\n' } else { ' ' }) + ).collect::>().join(""); + write!(f, "{}", str) + } +} + +impl From<&str> for BingoCard { + fn from(s: &str) -> Self { + let mut nums = Vec::with_capacity(25); + s.lines().for_each( + |l| l.split_whitespace().for_each( + |n| nums.push((n.parse().expect("Malformed input"), false)) + ) + ); + BingoCard { ingame: true, nums } + } +} + +/* AOC21 Day 4: https://adventofcode.com/2021/day/4 */ +fn main() { + let input = Path::new("resources").join("input.txt"); + let content = fs::read_to_string(input).expect("Unable to read input file"); + let report: Vec<&str> = content.split("\n\n").collect(); + let draws: Vec = report[0].split(",").map(|x| x.parse().expect("Malformed input")).collect(); + let cards: Vec = report[1..].iter().map(|&c| BingoCard::from(c)).collect(); + println!("Ex1: The result is {}", Bingo { cards: cards.clone() }.simulate(&draws)); + println!("Ex1: The result is {}", Bingo { cards }.simulate_all(&draws)); +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = "7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1 + +22 13 17 11 0 + 8 2 23 4 24 +21 9 14 16 7 + 6 10 3 18 5 + 1 12 20 15 19 + + 3 15 0 2 22 + 9 18 13 17 5 +19 8 7 25 23 +20 11 10 24 4 +14 21 16 12 6 + +14 21 17 24 4 +10 16 15 9 19 +18 8 23 26 20 +22 11 13 6 5 + 2 0 12 3 7"; + + #[test] + fn winning_score() { + let report: Vec<&str> = INPUT.split("\n\n").collect(); + let draws: Vec = report[0].split(",").map(|x| x.parse().expect("Malformed input")).collect(); + let cards: Vec = report[1..].iter().map(|&c| BingoCard::from(c)).collect(); + assert_eq!(4512, Bingo { cards }.simulate(&draws)) + } + + #[test] + fn last_winning_score() { + let report: Vec<&str> = INPUT.split("\n\n").collect(); + let draws: Vec = report[0].split(",").map(|x| x.parse().expect("Malformed input")).collect(); + let cards: Vec = report[1..].iter().map(|&c| BingoCard::from(c)).collect(); + assert_eq!(1924, Bingo { cards }.simulate_all(&draws)) + } +} -- cgit v1.2.3