day 12 part 1
This commit is contained in:
parent
2ee9c069d8
commit
0a4ce052ee
2 changed files with 1109 additions and 0 deletions
1000
inputs/day12.txt
Normal file
1000
inputs/day12.txt
Normal file
File diff suppressed because it is too large
Load diff
109
src/bin/day12.rs
Normal file
109
src/bin/day12.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
#![forbid(elided_lifetimes_in_paths, unsafe_code)]
|
||||
|
||||
use aoc23::read;
|
||||
use chumsky::{prelude::*, text::int};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum Cell {
|
||||
Working,
|
||||
Broken,
|
||||
Unknown
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
||||
choice((
|
||||
just('.').map(|_| Self::Working),
|
||||
just('#').map(|_| Self::Broken),
|
||||
just('?').map(|_| Self::Unknown)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
struct Row {
|
||||
cells: Vec<Cell>,
|
||||
expected: Vec<u32>
|
||||
}
|
||||
|
||||
impl Row {
|
||||
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
||||
Cell::parser()
|
||||
.repeated()
|
||||
.then_ignore(just(" "))
|
||||
.then(int(10).separated_by(just(",")))
|
||||
.map(|(cells, expected)| Self {
|
||||
cells,
|
||||
expected: expected
|
||||
.into_iter()
|
||||
.map(|num: String| num.parse().unwrap())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parser() -> impl Parser<char, Vec<Row>, Error = Simple<char>> {
|
||||
Row::parser()
|
||||
.then_ignore(just("\n"))
|
||||
.repeated()
|
||||
.then_ignore(end())
|
||||
}
|
||||
|
||||
fn combinations(
|
||||
peeked_cell: Option<Cell>,
|
||||
cells: &[Cell],
|
||||
current: u32,
|
||||
expected: &[u32]
|
||||
) -> u64 {
|
||||
let res = match (
|
||||
peeked_cell.or_else(|| cells.first().copied()),
|
||||
expected.first().copied()
|
||||
) {
|
||||
// streak but no more expectations
|
||||
(_, None) if current != 0 => 0,
|
||||
// everything empty, everything fine
|
||||
(None, None) => 1,
|
||||
// no more cells with expected containing just the current streak
|
||||
(None, Some(expectation)) if expectation == current && expected.len() == 1 => 1,
|
||||
// no more cells but expected doesn't match
|
||||
(None, Some(_)) => 0,
|
||||
|
||||
// working cell with no current streak
|
||||
(Some(Cell::Working), _) if current == 0 => {
|
||||
combinations(None, &cells[1 ..], 0, expected)
|
||||
},
|
||||
// working cell with current streak that is expected
|
||||
(Some(Cell::Working), Some(expectation)) if expectation == current => {
|
||||
combinations(None, &cells[1 ..], 0, &expected[1 ..])
|
||||
},
|
||||
// working cell with current streak that doesn't match
|
||||
(Some(Cell::Working), _) => 0,
|
||||
|
||||
// broken cell
|
||||
(Some(Cell::Broken), _) => {
|
||||
combinations(None, &cells[1 ..], current + 1, expected)
|
||||
},
|
||||
|
||||
// unknown cell
|
||||
(Some(Cell::Unknown), _) => {
|
||||
combinations(Some(Cell::Working), cells, current, expected)
|
||||
+ combinations(Some(Cell::Broken), cells, current, expected)
|
||||
},
|
||||
};
|
||||
// eprintln!(
|
||||
// "combinations({peeked_cell:?}, {cells:?}, {current}, {expected:?}) = {res}"
|
||||
// );
|
||||
res
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let grid = read("inputs/day12.txt", parser())?;
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
grid.iter()
|
||||
.map(|row| combinations(None, &row.cells, 0, &row.expected))
|
||||
.sum::<u64>()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue