mirror of
https://github.com/anthonyoteri/advent-of-code-2023.git
synced 2026-06-05 18:56:53 -04:00
@@ -22,6 +22,7 @@ dhat = "0.3.2"
|
|||||||
env_logger = "0.10.1"
|
env_logger = "0.10.1"
|
||||||
test-log = "0.2.13"
|
test-log = "0.2.13"
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
|
memoize = "0.4.1"
|
||||||
|
|
||||||
|
|
||||||
[profile.flamegraph]
|
[profile.flamegraph]
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ miette = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
dhat = { workspace = true }
|
dhat = { workspace = true }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
|
rayon = { workspace = true }
|
||||||
|
memoize = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
divan = { workspace = true }
|
divan = { workspace = true }
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ fn main() {
|
|||||||
|
|
||||||
#[divan::bench]
|
#[divan::bench]
|
||||||
fn part1() {
|
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]
|
#[divan::bench]
|
||||||
fn part2() {
|
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
@@ -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;
|
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]
|
#[tracing::instrument]
|
||||||
pub fn process(input: &str) -> miette::Result<u64, AocError> {
|
pub fn process(input: &str) -> miette::Result<usize, AocError> {
|
||||||
Ok(0)
|
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)]
|
#[cfg(test)]
|
||||||
@@ -12,7 +90,7 @@ mod tests {
|
|||||||
#[test_log::test]
|
#[test_log::test]
|
||||||
fn test_process() -> miette::Result<()> {
|
fn test_process() -> miette::Result<()> {
|
||||||
let input = include_str!("../test-input.txt");
|
let input = include_str!("../test-input.txt");
|
||||||
assert_eq!(0, process(input)?);
|
assert_eq!(525152, process(input)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user