day 12
This commit is contained in:
parent
68ee92a178
commit
994be7e629
|
@ -143,6 +143,14 @@ dependencies = [
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day-12"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"indoc",
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deprecate-until"
|
name = "deprecate-until"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -1,16 +1,10 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"day-01",
|
"day-*"
|
||||||
"day-02",
|
]
|
||||||
"day-03",
|
exclude = [
|
||||||
"day-05",
|
"day-04"
|
||||||
"day-06",
|
|
||||||
"day-07",
|
|
||||||
"day-08",
|
|
||||||
"day-09",
|
|
||||||
"day-10",
|
|
||||||
"day-11"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "day-12"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nom.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
indoc.workspace = true
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,116 @@
|
||||||
|
use nom::{branch::alt, character::complete, combinator::value, multi::many1};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{}", part1(include_str!("./input.txt")));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> u32 {
|
||||||
|
input.lines().map(process_line).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_line(line: &str) -> u32 {
|
||||||
|
let (springs_str, group_size_str) = line.split_once(' ').expect("Invalid input");
|
||||||
|
|
||||||
|
let group_size = group_size_str
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.parse::<usize>().expect("invalid char as number"))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let springs = many1(alt((
|
||||||
|
value(
|
||||||
|
SpringStatus::Operational,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('.'),
|
||||||
|
),
|
||||||
|
value(
|
||||||
|
SpringStatus::Damaged,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('#'),
|
||||||
|
),
|
||||||
|
value(
|
||||||
|
SpringStatus::Unknown,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('?'),
|
||||||
|
),
|
||||||
|
)))(springs_str)
|
||||||
|
.expect("Invalid input")
|
||||||
|
.1;
|
||||||
|
|
||||||
|
let spring_amount = springs.len();
|
||||||
|
let groups_amount = group_size.len();
|
||||||
|
let mut dp = vec![vec![vec![0; spring_amount + 1]; groups_amount + 1]; spring_amount + 1];
|
||||||
|
|
||||||
|
dp[spring_amount][groups_amount][0] = 1;
|
||||||
|
dp[spring_amount][groups_amount - 1][group_size[groups_amount - 1]] = 1;
|
||||||
|
|
||||||
|
for pos in (0..spring_amount).rev() {
|
||||||
|
for (group, &max_count) in group_size.iter().enumerate() {
|
||||||
|
// try iteratively all possible counts for the current group
|
||||||
|
for count in 0..=max_count {
|
||||||
|
// try both operational and damaged for each position
|
||||||
|
for &c in &[SpringStatus::Operational, SpringStatus::Damaged] {
|
||||||
|
// only proceed if the spring is of the chosen type or unknown
|
||||||
|
if springs[pos] == c || springs[pos] == SpringStatus::Unknown {
|
||||||
|
if c == SpringStatus::Operational && count == 0 {
|
||||||
|
// if operational and count is 0, then add the value from the next position because
|
||||||
|
// there is no new combination
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group][0];
|
||||||
|
} else if c == SpringStatus::Operational && group_size[group] == count {
|
||||||
|
// if operational and count is equal to the group size, then add the value from the
|
||||||
|
// next position and next group
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group + 1][0];
|
||||||
|
} else if c == SpringStatus::Damaged {
|
||||||
|
// if damaged, then add the value from the next position and next count
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group][count + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matches!(
|
||||||
|
springs[pos],
|
||||||
|
SpringStatus::Operational | SpringStatus::Unknown
|
||||||
|
) {
|
||||||
|
dp[pos][groups_amount][0] += dp[pos + 1][groups_amount][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dp[0][0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum SpringStatus {
|
||||||
|
Operational,
|
||||||
|
Damaged,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part1() {
|
||||||
|
assert_eq!(
|
||||||
|
part1(indoc!(
|
||||||
|
"
|
||||||
|
???.### 1,1,3
|
||||||
|
.??..??...?##. 1,1,3
|
||||||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
????.#...#... 4,1,1
|
||||||
|
????.######..#####. 1,6,5
|
||||||
|
?###???????? 3,2,1
|
||||||
|
"
|
||||||
|
)),
|
||||||
|
21
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_process_line_part1() {
|
||||||
|
assert_eq!(process_line("???.### 1,1,3"), 1);
|
||||||
|
assert_eq!(process_line(".??..??...?##. 1,1,3"), 4);
|
||||||
|
assert_eq!(process_line("?#?#?#?#?#?#?#? 1,3,1,6"), 1);
|
||||||
|
assert_eq!(process_line("????.#...#... 4,1,1"), 1);
|
||||||
|
assert_eq!(process_line("????.######..#####. 1,6,5"), 4);
|
||||||
|
assert_eq!(process_line("?###???????? 3,2,1"), 10);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
use std::vec;
|
||||||
|
|
||||||
|
use nom::{branch::alt, character::complete, combinator::value, multi::many1};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{}", part2(include_str!("./input.txt")));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> u64 {
|
||||||
|
input.lines().map(process_line).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_line(line: &str) -> u64 {
|
||||||
|
let (springs_str, group_size_str) = line.split_once(' ').expect("Invalid input");
|
||||||
|
|
||||||
|
let group_size = group_size_str
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.parse::<usize>().expect("invalid char as number"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.repeat(5);
|
||||||
|
|
||||||
|
let springs = many1(alt((
|
||||||
|
value(
|
||||||
|
SpringStatus::Operational,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('.'),
|
||||||
|
),
|
||||||
|
value(
|
||||||
|
SpringStatus::Damaged,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('#'),
|
||||||
|
),
|
||||||
|
value(
|
||||||
|
SpringStatus::Unknown,
|
||||||
|
complete::char::<&str, nom::error::Error<&str>>('?'),
|
||||||
|
),
|
||||||
|
)))(springs_str)
|
||||||
|
.expect("Invalid input")
|
||||||
|
.1;
|
||||||
|
|
||||||
|
let springs = vec![
|
||||||
|
springs.clone(),
|
||||||
|
vec![SpringStatus::Unknown],
|
||||||
|
springs.clone(),
|
||||||
|
vec![SpringStatus::Unknown],
|
||||||
|
springs.clone(),
|
||||||
|
vec![SpringStatus::Unknown],
|
||||||
|
springs.clone(),
|
||||||
|
vec![SpringStatus::Unknown],
|
||||||
|
springs,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let spring_amount = springs.len();
|
||||||
|
let groups_amount = group_size.len();
|
||||||
|
|
||||||
|
let mut dp = vec![vec![vec![0; spring_amount + 1]; groups_amount + 1]; spring_amount + 1];
|
||||||
|
|
||||||
|
dp[spring_amount][groups_amount][0] = 1;
|
||||||
|
dp[spring_amount][groups_amount - 1][group_size[groups_amount - 1]] = 1;
|
||||||
|
|
||||||
|
for pos in (0..spring_amount).rev() {
|
||||||
|
for (group, &max_count) in group_size.iter().enumerate() {
|
||||||
|
// try iteratively all possible counts for the current group
|
||||||
|
for count in 0..=max_count {
|
||||||
|
// try both operational and damaged for each position
|
||||||
|
for &c in &[SpringStatus::Operational, SpringStatus::Damaged] {
|
||||||
|
// only proceed if the spring is of the chosen type or unknown
|
||||||
|
if springs[pos] == c || springs[pos] == SpringStatus::Unknown {
|
||||||
|
if c == SpringStatus::Operational && count == 0 {
|
||||||
|
// if operational and count is 0, then add the value from the next position because
|
||||||
|
// there is no new combination
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group][0];
|
||||||
|
} else if c == SpringStatus::Operational && group_size[group] == count {
|
||||||
|
// if operational and count is equal to the group size, then add the value from the
|
||||||
|
// next position and next group
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group + 1][0];
|
||||||
|
} else if c == SpringStatus::Damaged {
|
||||||
|
// if damaged, then add the value from the next position and next count
|
||||||
|
dp[pos][group][count] += dp[pos + 1][group][count + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matches!(
|
||||||
|
springs[pos],
|
||||||
|
SpringStatus::Operational | SpringStatus::Unknown
|
||||||
|
) {
|
||||||
|
dp[pos][groups_amount][0] += dp[pos + 1][groups_amount][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dp[0][0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum SpringStatus {
|
||||||
|
Operational,
|
||||||
|
Damaged,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part2() {
|
||||||
|
assert_eq!(
|
||||||
|
part2(indoc!(
|
||||||
|
"
|
||||||
|
???.### 1,1,3
|
||||||
|
.??..??...?##. 1,1,3
|
||||||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
????.#...#... 4,1,1
|
||||||
|
????.######..#####. 1,6,5
|
||||||
|
?###???????? 3,2,1
|
||||||
|
"
|
||||||
|
)),
|
||||||
|
525152
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_process_line_part2() {
|
||||||
|
assert_eq!(process_line("???.### 1,1,3"), 1);
|
||||||
|
assert_eq!(process_line(".??..??...?##. 1,1,3"), 16384);
|
||||||
|
assert_eq!(process_line("?#?#?#?#?#?#?#? 1,3,1,6"), 1);
|
||||||
|
assert_eq!(process_line("????.#...#... 4,1,1"), 16);
|
||||||
|
assert_eq!(process_line("????.######..#####. 1,6,5"), 2500);
|
||||||
|
assert_eq!(process_line("?###???????? 3,2,1"), 506250);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue