Skip to content

Commit

Permalink
submit day 12 part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
dcastil committed Dec 18, 2023
1 parent 27aa2e1 commit 21d44a4
Showing 1 changed file with 115 additions and 3 deletions.
118 changes: 115 additions & 3 deletions src/bin/12.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

advent_of_code::solution!(12);

pub fn part_one(input: &str) -> Option<usize> {
Expand All @@ -14,7 +16,23 @@ pub fn part_one(input: &str) -> Option<usize> {
}

pub fn part_two(input: &str) -> Option<usize> {
None
let mut cache = HashMap::new();
let mut records = Vec::new();

let sum_arrangements = input
.lines()
.map(|line| {
let record = Record::from_line_unfolded(line);

let arrangements = record.arrangements_count_with_cache(&mut cache);

records.push(record);

arrangements
})
.sum();

Some(sum_arrangements)
}

#[derive(Debug)]
Expand Down Expand Up @@ -43,9 +61,40 @@ impl Record {
}
}

fn from_line_unfolded(line: &str) -> Record {
let mut line_iterator = line.split_ascii_whitespace();
let sequence_string = line_iterator.next().unwrap();
let fill_counts_string = line_iterator.next().unwrap();

let mut sequence = Vec::new();

for index in 0..5 {
if index != 0 {
sequence.push(Field::Unknown);
}

sequence.extend(sequence_string.bytes().map(Field::from_char))
}

Record {
sequence,
fill_counts: (0..5)
.flat_map(|_| {
fill_counts_string
.split(',')
.map(|number_string| number_string.parse().unwrap())
})
.collect(),
}
}

fn arrangements_count(&self) -> usize {
RecordSlice::from_record(self).arrangements_count()
}

fn arrangements_count_with_cache(&self, cache: &mut HashMap<String, usize>) -> usize {
RecordSlice::from_record(self).arrangements_count_with_cache(cache)
}
}

struct RecordSlice<'a> {
Expand Down Expand Up @@ -91,6 +140,47 @@ impl RecordSlice<'_> {
}
}

fn arrangements_count_with_cache(&self, cache: &mut HashMap<String, usize>) -> usize {
if let Some(&next_fill_count) = self.next_fill_count() {
let mut arrangements_count = 0;

for index in 0..=self.index_end_for_next_fill_count() {
let field = &self.sequence[index];

if field.is_empty() {
continue;
}

let sub_arrangements_count =
self.fill(index, next_fill_count).map_or(0, |record_slice| {
let key = record_slice.to_key();

if let Some(&arrangements) = cache.get(&key) {
arrangements
} else {
let arrangements = record_slice.arrangements_count_with_cache(cache);

cache.insert(key, arrangements);

arrangements
}
});

arrangements_count += sub_arrangements_count;

if field.is_filled() {
break;
}
}

arrangements_count
} else if self.sequence.iter().all(|field| field.can_be_empty()) {
1
} else {
0
}
}

fn next_fill_count(&self) -> Option<&usize> {
self.fill_counts.first()
}
Expand Down Expand Up @@ -133,9 +223,23 @@ impl RecordSlice<'_> {
fill_counts: &self.fill_counts[1..],
}
}

fn to_key(&self) -> String {
let mut key = String::new();

for field in self.sequence {
key.push(field.to_char());
}

for fill_count in self.fill_counts {
key.push_str(&fill_count.to_string());
}

key
}
}

#[derive(PartialEq, Debug)]
#[derive(PartialEq, Eq, Hash, Debug)]
enum Field {
Empty,
Filled,
Expand All @@ -152,6 +256,14 @@ impl Field {
}
}

fn to_char(&self) -> char {
match self {
Field::Filled => '#',
Field::Empty => '.',
Field::Unknown => '?',
}
}

fn is_empty(&self) -> bool {
*self == Field::Empty
}
Expand Down Expand Up @@ -186,6 +298,6 @@ mod tests {
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None);
assert_eq!(result, Some(525152));
}
}

0 comments on commit 21d44a4

Please sign in to comment.