Day 12 - Part 2

Signed-off-by: Anthony Oteri <anthony.oteri@gmail.com>
This commit is contained in:
Anthony Oteri
2023-12-12 14:55:22 -05:00
parent 98c9b7e4a9
commit 7b73f3f020
4 changed files with 86 additions and 5 deletions
+1
View File
@@ -22,6 +22,7 @@ dhat = "0.3.2"
env_logger = "0.10.1"
test-log = "0.2.13"
regex = "1.10.2"
memoize = "0.4.1"
[profile.flamegraph]
+2
View File
@@ -14,6 +14,8 @@ miette = { workspace = true }
thiserror = { workspace = true }
dhat = { workspace = true }
regex = { workspace = true }
rayon = { workspace = true }
memoize = { workspace = true }
[dev-dependencies]
divan = { workspace = true }
+2 -2
View File
@@ -6,10 +6,10 @@ fn main() {
#[divan::bench]
fn part1() {
part1::process(divan::black_box(include_str!("../test-input.txt"))).unwrap();
part1::process(divan::black_box(include_str!("../input.txt"))).unwrap();
}
#[divan::bench]
fn part2() {
part2::process(divan::black_box(include_str!("../test-input.txt"))).unwrap();
part2::process(divan::black_box(include_str!("../input.txt"))).unwrap();
}
+81 -3
View File
@@ -1,8 +1,86 @@
use nom::{
branch::alt,
bytes::complete::{tag, take_until},
character::complete::{self, line_ending, space1},
combinator::eof,
multi::{many1, separated_list1},
sequence::{self, terminated},
IResult,
};
use rayon::prelude::*;
use crate::error::AocError;
fn parse_input(input: &str) -> IResult<&str, &str> {
terminated(take_until(" "), space1)(input)
}
fn parse_limits(input: &str) -> IResult<&str, Vec<usize>> {
let (input, limits) = separated_list1(tag(","), complete::u32)(input)?;
Ok((input, limits.into_iter().map(|n| n as usize).collect()))
}
fn parser(input: &str) -> IResult<&str, Vec<(&str, Vec<usize>)>> {
many1(terminated(
sequence::tuple((parse_input, parse_limits)),
alt((line_ending, eof)),
))(input)
}
#[memoize::memoize]
fn count(input: String, limits: Vec<usize>) -> usize {
if input.is_empty() {
if limits.is_empty() {
return 1;
} else {
return 0;
}
}
if limits.is_empty() {
if input.contains('#') {
return 0;
} else {
return 1;
}
}
let mut n = 0;
if input.starts_with('.') || input.starts_with('?') {
n += count(input[1..].to_string(), limits.clone());
}
if (input.starts_with('#') || input.starts_with('?')) && limits[0] <= input.len()
&& !input.get(..limits[0]).unwrap().contains('.') && (limits[0] == input.len() || input.chars().nth(limits[0]).unwrap() != '#') {
n += count(
input.get(limits[0] + 1..).unwrap_or_default().to_string(),
limits[1..].to_vec(),
);
}
n
}
#[tracing::instrument]
pub fn process(input: &str) -> miette::Result<u64, AocError> {
Ok(0)
pub fn process(input: &str) -> miette::Result<usize, AocError> {
let (_, parsed) = parser(input).unwrap();
Ok(parsed
.par_iter()
.map(|(string, limits)| {
let string = std::iter::repeat(string)
.take(5)
.cloned()
.collect::<Vec<&str>>()
.join("?");
let limits = limits
.iter()
.cycle()
.take(5 * limits.len())
.cloned()
.collect::<Vec<_>>();
count(string.clone(), limits)
})
.sum())
}
#[cfg(test)]
@@ -12,7 +90,7 @@ mod tests {
#[test_log::test]
fn test_process() -> miette::Result<()> {
let input = include_str!("../test-input.txt");
assert_eq!(0, process(input)?);
assert_eq!(525152, process(input)?);
Ok(())
}
}