From 3daa7a1ad11faacea165b394c63ff575fa2142ad Mon Sep 17 00:00:00 2001 From: George Thomas Date: Fri, 9 Jan 2026 13:39:14 +0000 Subject: [PATCH] Solve day 6 in Rust --- rust/main.rs | 4 +- rust/puzzles/day6.rs | 137 +++++++++++++++++++++++++++++++++++++++++++ rust/puzzles/mod.rs | 1 + 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 rust/puzzles/day6.rs diff --git a/rust/main.rs b/rust/main.rs index 96909a8..58ff396 100644 --- a/rust/main.rs +++ b/rust/main.rs @@ -6,15 +6,17 @@ use puzzles::day2; use puzzles::day3; use puzzles::day4; use puzzles::day5; +use puzzles::day6; use std::fs; use std::time::{Duration, Instant}; -const PUZZLES: [&dyn SomePuzzle; 5] = [ +const PUZZLES: [&dyn SomePuzzle; 6] = [ &day1::PUZZLE, &day2::PUZZLE, &day3::PUZZLE, &day4::PUZZLE, &day5::PUZZLE, + &day6::PUZZLE, ]; fn main() { diff --git a/rust/puzzles/day6.rs b/rust/puzzles/day6.rs new file mode 100644 index 0000000..e7643df --- /dev/null +++ b/rust/puzzles/day6.rs @@ -0,0 +1,137 @@ +use crate::puzzle::Puzzle; +use itertools::Itertools; +use nom::{ + Parser, + branch::alt, + character::complete::{char, newline, satisfy, space1}, + combinator::{eof, value}, + error::Error, + multi::{many1, separated_list1}, + sequence::terminated, +}; +use std::ops::{Add, Mul}; + +pub const PUZZLE: Puzzle<(Vec, Vec>>), 2> = Puzzle { + number: 6, + parser: |input| { + terminated::<_, _, Error<&str>, _, _>( + ( + terminated( + separated_list1( + newline, + many1(alt(( + satisfy(|c| c.is_digit(10)).map(|c| Some(c as u8 - '0' as u8)), + value(None, char(' ')), + ))), + ), + newline, + ), + terminated( + terminated( + separated_list1( + space1, + alt((value(Op::Multiply, char('*')), value(Op::Add, char('+')))), + ), + space1, + ), + newline, + ), + ), + eof, + ) + .map(|(grid, ops)| (ops, grid)) + .parse(input) + .unwrap() + .1 + }, + parts: [ + |(ops, grid)| { + transpose( + &grid + .iter() + .map(|row| { + row.group_somes() + .iter() + .filter(|v| !v.is_empty()) + .map(|digits| digits_to_int(&digits)) + .collect() + }) + .collect::>(), + ) + .iter() + .zip(ops.iter()) + .map(|(list, op)| op.apply_to_list(list)) + .sum::() + .to_string() + }, + |(ops, grid)| { + transpose(grid) + .iter() + .map(|l| { + if l.iter().all(|x| x.is_none()) { + None + } else { + Some(digits_to_int( + &l.iter().filter_map(|x| *x).collect::>(), + )) + } + }) + .collect::>() + .group_somes() + .iter() + .zip(ops.iter()) + .map(|(list, op)| op.apply_to_list(list)) + .sum::() + .to_string() + }, + ], +}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Op { + Add, + Multiply, +} +impl Op { + fn apply + Mul>(self, a: N, b: N) -> N { + match self { + Op::Add => a + b, + Op::Multiply => a * b, + } + } + fn unit>(self) -> N { + match self { + Op::Add => N::from(0), + Op::Multiply => N::from(1), + } + } + fn apply_to_list(self, list: &[usize]) -> usize { + list.iter().fold(self.unit(), |acc, &x| self.apply(acc, x)) + } +} + +trait GroupSomes { + fn group_somes(&self) -> Vec>; +} +impl GroupSomes for [Option] { + fn group_somes(&self) -> Vec> { + self.iter() + .chunk_by(|x| x.is_some()) + .into_iter() + .filter_map(|(is_some, group)| { + is_some.then(|| group.filter_map(|x| x.clone()).collect()) + }) + .collect() + } +} + +fn transpose(grid: &[Vec]) -> Vec> { + let w = grid.iter().map(|r| r.len()).max().unwrap_or(0); + (0..w) + .map(|x| grid.iter().filter_map(|r| r.get(x).cloned()).collect()) + .collect() +} + +fn digits_to_int(digits: &[u8]) -> usize { + digits.iter().fold(0, |acc, &d| acc * 10 + (d as usize)) +} diff --git a/rust/puzzles/mod.rs b/rust/puzzles/mod.rs index f5551d6..92a3a4b 100644 --- a/rust/puzzles/mod.rs +++ b/rust/puzzles/mod.rs @@ -3,3 +3,4 @@ pub(crate) mod day2; pub(crate) mod day3; pub(crate) mod day4; pub(crate) mod day5; +pub(crate) mod day6;