garnet/rust/puzzles/day7.rs

90 lines
2.8 KiB
Rust
Raw Normal View History

2026-01-12 18:23:58 +00:00
use crate::puzzle::Puzzle;
use itertools::Itertools;
use nom::{
Parser,
branch::alt,
character::complete::{char, newline},
combinator::{eof, value},
error::Error,
multi::{many1, separated_list1},
sequence::terminated,
};
use std::collections::{HashMap, HashSet};
pub const PUZZLE: Puzzle<(usize, Vec<HashSet<usize>>), 2> = Puzzle {
number: 7,
parser: |_, input| {
2026-01-12 18:23:58 +00:00
terminated::<_, _, Error<&str>, _, _>(
terminated(
(
terminated(
many1(alt((value(false, char('.')), value(true, char('S'))))),
newline,
)
.map_opt(|v| v.into_iter().position(|b| b)),
separated_list1(
newline,
many1(alt((value(false, char('.')), value(true, char('^'))))),
)
.map(|rows| {
rows.into_iter()
.map(|row| {
row.into_iter()
.enumerate()
2026-01-13 14:16:43 +00:00
.filter_map(|(i, b)| if b { Some(i) } else { None })
2026-01-12 18:23:58 +00:00
.collect()
})
.collect()
}),
),
newline,
),
eof,
)
.parse(input)
.unwrap()
.1
},
parts: [
|(start, splitter_rows)| {
let mut beams = HashSet::from([*start]);
let mut count = 0;
for splitters in splitter_rows {
beams = beams
.iter()
.flat_map(|x| {
if splitters.contains(x) {
count += 1;
vec![x - 1, x + 1]
} else {
vec![*x]
}
})
.collect();
}
count.to_string()
},
|(start, splitter_rows)| {
let mut beams = HashMap::from([(*start, 1)]);
for splitters in splitter_rows {
beams = beams
.into_iter()
.flat_map(|(x, n)| {
if splitters.contains(&x) {
vec![x - 1, x + 1]
} else {
vec![x]
}
.into_iter()
2026-01-13 14:16:40 +00:00
.map(move |x1| (x1, n))
2026-01-12 18:23:58 +00:00
})
.into_group_map()
.into_iter()
.map(|(k, vs)| (k, vs.into_iter().sum()))
.collect();
}
beams.values().sum::<usize>().to_string()
},
],
};