Created
December 4, 2021 22:27
-
-
Save and-reas-se/0a4c77f150715213e753b5f9ce8a7238 to your computer and use it in GitHub Desktop.
Advent of Code day 4 in rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fn main() { | |
let input_file = std::env::args().nth(1).expect("Input filename missing"); | |
let input = std::fs::read_to_string(input_file).expect("Error reading file"); | |
let numbers = input | |
.lines() | |
.next() | |
.unwrap() | |
.split(',') | |
.map(|num| num.parse().expect("invalid number")) | |
.collect(); | |
let mut cards = Vec::new(); | |
let mut buffer = String::new(); | |
let mut count = 0; | |
for line in input.lines().skip(1) { | |
count += 1; | |
buffer.push_str(line); | |
buffer.push(' '); | |
if count == 6 { | |
cards.push(BingoCard::new_from_str(&buffer)); | |
buffer.clear(); | |
count = 0; | |
} | |
} | |
let answer = question1(&numbers, &mut cards.clone()); | |
println!("Answer to question 1: {}", answer); | |
let answer = question2(&numbers, &mut cards); | |
println!("Answer to question 1: {}", answer); | |
} | |
fn question1(numbers: &Vec<u32>, cards: &mut Vec<BingoCard>) -> u32 { | |
for number in numbers { | |
for card in cards.iter_mut() { | |
if let Some(score) = card.mark(*number) { | |
return score; | |
} | |
} | |
} | |
0 | |
} | |
fn question2(numbers: &Vec<u32>, cards: &mut Vec<BingoCard>) -> u32 { | |
let mut last_score = 0; | |
for number in numbers { | |
for card in cards.iter_mut().filter(|item| !item.is_won()) { | |
if let Some(score) = card.mark(*number) { | |
last_score = score; | |
} | |
} | |
} | |
last_score | |
} | |
#[derive(Debug, Clone)] | |
struct BingoCard { | |
squares: Vec<u32>, | |
marks: [bool; 25], | |
row_marks: [u32; 5], | |
col_marks: [u32; 5], | |
is_won: bool, | |
} | |
impl BingoCard { | |
/// NOTE: This will panic if the bingo square is not 5x5 | |
fn new_from_str(text: &str) -> Self { | |
let squares: Vec<u32> = text | |
.split_whitespace() | |
.map(|num| num.parse().expect("error parsing bingo square")) | |
.collect(); | |
assert_eq!(squares.len(), 25, "invalid bingo board size: {:#?}", text); | |
Self { | |
squares, | |
marks: [false; 25], | |
row_marks: [0; 5], | |
col_marks: [0; 5], | |
is_won: false, | |
} | |
} | |
fn is_won(&self) -> bool { | |
self.is_won | |
} | |
/// returns Some(score) if we won, otherwise returns None | |
/// assumes numbers in bingo squares are unique | |
fn mark(&mut self, number: u32) -> Option<u32> { | |
if let Some((idx, _)) = self | |
.squares | |
.iter() | |
.enumerate() | |
.find(|(_, value)| **value == number) | |
{ | |
let col_idx = idx % 5; | |
let row_idx = idx / 5; | |
self.marks[idx] = true; | |
self.row_marks[row_idx] += 1; | |
self.col_marks[col_idx] += 1; | |
if self.row_marks[row_idx] == 5 || self.col_marks[col_idx] == 5 { | |
self.is_won = true; | |
return Some(self.sum_of_unmarked_squares() * number); | |
} | |
} | |
None | |
} | |
fn sum_of_unmarked_squares(&self) -> u32 { | |
self.squares | |
.iter() | |
.enumerate() | |
.filter(|(idx, _)| !self.marks[*idx]) | |
.map(|(_, value)| value) | |
.sum() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment