summaryrefslogtreecommitdiff
path: root/2023/src/bin/day_4.rs
diff options
context:
space:
mode:
Diffstat (limited to '2023/src/bin/day_4.rs')
-rw-r--r--2023/src/bin/day_4.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/2023/src/bin/day_4.rs b/2023/src/bin/day_4.rs
new file mode 100644
index 0000000..7f5af6b
--- /dev/null
+++ b/2023/src/bin/day_4.rs
@@ -0,0 +1,92 @@
+use nom::{
+ bytes::complete::tag,
+ character::complete::{line_ending, space1, u32 as nom_u32},
+ combinator::map,
+ multi::separated_list1,
+ sequence::tuple,
+ IResult,
+};
+use std::{collections::BTreeSet, fs};
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let input = fs::read_to_string("inputs/day_4.txt")?;
+ let parsed = Scratchcards::parser(&input).unwrap().1;
+ dbg!(&parsed.points());
+ dbg!(&parsed.scratchcard_explosion_sum());
+
+ Ok(())
+}
+
+#[derive(Debug)]
+struct Scratchcards(Vec<Scratchcard>);
+
+#[derive(Debug)]
+struct Scratchcard {
+ winning: BTreeSet<u32>,
+ owned: BTreeSet<u32>,
+}
+
+impl Scratchcards {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(
+ separated_list1(line_ending, Scratchcard::parser),
+ Scratchcards,
+ )(input)
+ }
+
+ fn points(&self) -> usize {
+ self.0.iter().map(|card| card.points()).sum()
+ }
+
+ fn scratchcard_explosion_sum(&self) -> u64 {
+ let mut scratchcard_pile = vec![1_u64.into(); self.0.len()];
+
+ for i in 0..scratchcard_pile.len() {
+ let points = self.0[i].winning_numbers();
+ let new_scratchcards: u64 = scratchcard_pile[i];
+ for offset in 0..points {
+ if let Some(pile) = scratchcard_pile.get_mut(i + 1 + offset) {
+ *pile += new_scratchcards;
+ }
+ }
+ }
+
+ scratchcard_pile.into_iter().sum()
+ }
+}
+
+impl Scratchcard {
+ fn parser(input: &str) -> IResult<&str, Self> {
+ map(
+ tuple((
+ tag("Card"),
+ space1,
+ nom_u32,
+ tag(":"),
+ space1,
+ separated_list1(space1, nom_u32),
+ space1,
+ tag("|"),
+ space1,
+ separated_list1(space1, nom_u32),
+ )),
+ |(_, _, _, _, _, winning, _, _, _, owned)| Scratchcard {
+ winning: winning.into_iter().collect(),
+ owned: owned.into_iter().collect(),
+ },
+ )(input)
+ }
+
+ fn winning_numbers(&self) -> usize {
+ self.winning.intersection(&self.owned).count()
+ }
+
+ fn points(&self) -> usize {
+ let winning_numbers = self.winning_numbers();
+ if winning_numbers > 0 {
+ 2_usize.pow(winning_numbers as u32 - 1)
+ } else {
+ 0
+ }
+ }
+}