This commit is contained in:
Kristofers Solo 2023-12-16 20:30:23 +02:00
parent 82b5c6ebcb
commit 0ab91c4a2a
3 changed files with 95 additions and 240 deletions

45
2023/Cargo.lock generated
View File

@ -97,9 +97,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.3" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"crossbeam-epoch", "crossbeam-epoch",
@ -108,22 +108,21 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.15" version = "0.9.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
"crossbeam-utils", "crossbeam-utils",
"memoffset", "memoffset",
"scopeguard",
] ]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.16" version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -203,6 +202,8 @@ name = "day-12"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"color-eyre", "color-eyre",
"itertools",
"nom",
] ]
[[package]] [[package]]
@ -213,9 +214,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "eyre" name = "eyre"
version = "0.6.9" version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799"
dependencies = [ dependencies = [
"indenter", "indenter",
"once_cell", "once_cell",
@ -262,9 +263,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.150" version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -330,9 +331,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.18.0" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "owo-colors" name = "owo-colors"
@ -390,12 +391,6 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@ -407,9 +402,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.39" version = "2.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -418,18 +413,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.50" version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.50" version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -7,3 +7,5 @@ edition = "2021"
[dependencies] [dependencies]
color-eyre.workspace = true color-eyre.workspace = true
itertools.workspace = true
nom.workspace = true

View File

@ -1,125 +1,89 @@
use std::str::FromStr;
use color_eyre::Result; use color_eyre::Result;
use itertools::{repeat_n, Itertools};
use nom::{
bytes::complete::{is_a, tag},
character::complete::{self, space1},
multi::separated_list1,
sequence::separated_pair,
IResult,
};
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug)]
enum SpringStatus { struct Puzzle {
Operational, spaces_to_fill: usize,
Unknown, line: String,
Damaged, batches: Vec<usize>,
} }
#[derive(Debug, Clone, PartialEq, Default)] impl Puzzle {
struct Spring { fn generate_permutations(&self) -> impl Iterator<Item = String> {
status: Vec<SpringStatus>, repeat_n([".", "#"].into_iter(), self.spaces_to_fill)
condition: Vec<usize>, .multi_cartesian_product()
} .map(|x| x.join(""))
impl Spring {
fn arragement_amount(&self) -> usize {
let mut combinations = vec![vec![]];
for status in &self.status {
let mut new_combinations = Vec::new();
for combination in &combinations {
match status {
SpringStatus::Operational => {
let mut new_combination = combination.clone();
new_combination.push(*status);
new_combinations.push(new_combination);
}
SpringStatus::Unknown => {
let mut new_combination = combination.clone();
new_combination.push(SpringStatus::Operational);
new_combinations.push(new_combination);
let mut new_combination = combination.clone();
new_combination.push(SpringStatus::Damaged);
new_combinations.push(new_combination);
}
SpringStatus::Damaged => {
let mut new_combination = combination.clone();
new_combination.push(*status);
new_combinations.push(new_combination);
}
}
}
combinations = new_combinations;
}
let combinations = combinations
.iter()
.map(|combination| {
let mut combination_status: Vec<usize> = Vec::new();
let mut count = 0;
combination.iter().for_each(|status| {
match status {
SpringStatus::Operational => {
if count > 0 {
combination_status.push(count);
}
count = 0;
}
SpringStatus::Damaged => count += 1,
SpringStatus::Unknown => unimplemented!("Should not happen"),
};
});
if count > 0 {
combination_status.push(count);
}
combination_status
})
.filter(|status| status == &self.condition);
combinations.count()
} }
}
impl FromStr for Spring { fn check_option(&self, option: &str) -> bool {
type Err = color_eyre::Report; let mut option_iter = option.chars();
fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> { let filled_option = self
let line = s.split_whitespace().collect::<Vec<_>>(); .line
let status = line
.first()
.unwrap()
.chars() .chars()
.map(|ch| match ch { .map(|ch| match ch {
'?' => SpringStatus::Unknown, '?' => option_iter
'.' => SpringStatus::Operational, .next()
'#' => SpringStatus::Damaged, .expect("Should have a len similar to needed gaps"),
_ => unreachable!(), value => value,
}) })
.collect::<Vec<_>>(); .collect::<String>();
let condition = line let counts = filled_option
.last() .chars()
.unwrap() .group_by(|ch| ch == &'#')
.split(',') .into_iter()
.map(|s| s.parse::<usize>().unwrap()) .filter_map(|(is_hashes, group)| is_hashes.then_some(group.into_iter().count()))
.collect::<Vec<_>>(); .collect_vec();
&self.batches[..] == &counts[..]
let mut new_status = status.clone();
let mut new_condition = condition.clone();
for _ in 0..4 {
new_status.push(SpringStatus::Unknown);
new_status.extend(status.clone().iter());
new_condition.extend(condition.clone().iter());
}
dbg!(&new_status, &new_condition);
Ok(Self {
status: new_status,
condition: new_condition,
})
} }
fn possible_solution_count(&self) -> usize {
let count = self
.generate_permutations()
.filter(|option| self.check_option(option))
.count();
count
}
}
fn parse_line(input: &str) -> IResult<&str, Puzzle> {
let (input, (line, batches)) = separated_pair(
is_a("?.#"),
space1,
separated_list1(tag(","), complete::u32),
)(input)?;
let expanded_line = std::iter::repeat(line).take(5).join("?");
let spaces_to_fill = expanded_line.chars().filter(|ch| ch != &'?').count();
Ok((
input,
Puzzle {
spaces_to_fill,
line: expanded_line,
batches: std::iter::repeat(batches)
.take(5)
.flatten()
.map(|x| x as usize)
.collect(),
},
))
} }
pub fn process(input: &str) -> Result<usize> { pub fn process(input: &str) -> Result<usize> {
let springs = input.lines().map(|line| { let puzzles = input
Spring::from_str(line) .lines()
.unwrap_or_default() .map(parse_line)
.arragement_amount() .collect::<std::result::Result<Vec<(&str, Puzzle)>, nom::Err<nom::error::Error<&str>>>>()
}); .expect("Parsisng to succeed");
Ok(springs.sum()) let sum = puzzles
.iter()
.map(|(_, puzzle)| puzzle.possible_solution_count());
Ok(sum.sum())
} }
#[cfg(test)] #[cfg(test)]
@ -137,110 +101,4 @@ mod tests {
assert_eq!(525152, process(input)?); assert_eq!(525152, process(input)?);
Ok(()) Ok(())
} }
#[test]
fn test_from_str() -> Result<()> {
let input = "???.### 1,1,3";
let spring = Spring::from_str(input)?;
assert_eq!(
vec![
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Operational,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Operational,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Operational,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Operational,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Unknown,
SpringStatus::Operational,
SpringStatus::Damaged,
SpringStatus::Damaged,
SpringStatus::Damaged,
],
spring.status
);
assert_eq!(
vec![1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3],
spring.condition
);
Ok(())
}
#[test]
fn test_line_1() -> Result<()> {
assert_eq!(1, Spring::from_str("???.### 1,1,3")?.arragement_amount());
Ok(())
}
#[test]
fn test_line_2() -> Result<()> {
assert_eq!(
16384,
Spring::from_str(".??..??...?##. 1,1,3")?.arragement_amount()
);
Ok(())
}
#[test]
fn test_line_3() -> Result<()> {
assert_eq!(
1,
Spring::from_str("?#?#?#?#?#?#?#? 1,3,1,6")?.arragement_amount()
);
Ok(())
}
#[test]
fn test_line_4() -> Result<()> {
assert_eq!(
16,
Spring::from_str("????.#...#... 4,1,1")?.arragement_amount()
);
Ok(())
}
#[test]
fn test_line_5() -> Result<()> {
assert_eq!(
2500,
Spring::from_str("????.######..#####. 1,6,5")?.arragement_amount()
);
Ok(())
}
#[test]
fn test_line_6() -> Result<()> {
assert_eq!(
506250,
Spring::from_str("?###???????? 3,2,1")?.arragement_amount()
);
Ok(())
}
} }