Day 12
This commit is contained in:
parent
4df00cc74d
commit
1bc006c82e
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,143 @@
|
|||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
||||
type Cache = HashMap<(usize, u32, usize), u64>;
|
||||
|
||||
fn try_get_consume(
|
||||
remaining_str: &[u8],
|
||||
curr_run: u32,
|
||||
remaining_spec: &[u32],
|
||||
cache: &mut Cache,
|
||||
) -> u64 {
|
||||
let cache_key = (remaining_str.len(), curr_run, remaining_spec.len());
|
||||
if cache.contains_key(&cache_key) {
|
||||
return *cache.get(&(cache_key)).unwrap();
|
||||
}
|
||||
let result = try_consume(remaining_str, curr_run, remaining_spec, cache);
|
||||
cache.insert(cache_key, result);
|
||||
return result;
|
||||
}
|
||||
fn try_consume(
|
||||
remaining_str: &[u8],
|
||||
curr_run: u32,
|
||||
remaining_spec: &[u32],
|
||||
cache: &mut Cache,
|
||||
) -> u64 {
|
||||
if !remaining_spec.is_empty()
|
||||
&& (remaining_spec.iter().sum::<u32>() + remaining_spec.len() as u32 - 1)
|
||||
> (remaining_str.len() as u32 + curr_run)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if remaining_str.is_empty() {
|
||||
if curr_run != 0 {
|
||||
if remaining_spec.len() != 1 || curr_run != remaining_spec[0] {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// No current run, check that the remaining spec is empty.
|
||||
if remaining_spec.is_empty() {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if remaining_spec.is_empty() && curr_run > 0 {
|
||||
return 0;
|
||||
}
|
||||
match remaining_str[0] {
|
||||
b'.' => {
|
||||
if curr_run == 0 {
|
||||
return try_get_consume(&remaining_str[1..], 0, &remaining_spec, cache);
|
||||
} else if curr_run == remaining_spec[0] {
|
||||
return try_get_consume(&remaining_str[1..], 0, &remaining_spec[1..], cache);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
b'#' => {
|
||||
return try_get_consume(&remaining_str[1..], curr_run + 1, remaining_spec, cache);
|
||||
}
|
||||
b'?' => {
|
||||
if remaining_spec.is_empty() {
|
||||
// This must be a .
|
||||
return try_get_consume(&remaining_str[1..], 0, &remaining_spec, cache);
|
||||
} else if curr_run == remaining_spec[0] {
|
||||
// This must be a .
|
||||
return try_get_consume(&remaining_str[1..], 0, &remaining_spec[1..], cache);
|
||||
} else if curr_run > 0 {
|
||||
// This must be a #
|
||||
return try_get_consume(&remaining_str[1..], curr_run + 1, &remaining_spec, cache);
|
||||
} else {
|
||||
// Try both
|
||||
let dot_cnt = try_get_consume(&remaining_str[1..], 0, &remaining_spec, cache);
|
||||
let hash_cnt = try_get_consume(&remaining_str[1..], 1, &remaining_spec, cache);
|
||||
|
||||
/*
|
||||
println!(
|
||||
"String: {:?}\nSpec: {:?}\nDot: {}, Hash: {}",
|
||||
std::str::from_utf8(remaining_str),
|
||||
remaining_spec,
|
||||
dot_cnt,
|
||||
hash_cnt
|
||||
);
|
||||
*/
|
||||
return dot_cnt + hash_cnt;
|
||||
}
|
||||
}
|
||||
_ => panic!("Unexpected character"),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_record(record: &(Vec<u8>, Vec<u32>)) -> u64 {
|
||||
let mut cache: Cache = HashMap::new();
|
||||
try_consume(&record.0, 0, &record.1, &mut cache)
|
||||
}
|
||||
|
||||
fn check_records(records: Vec<(Vec<u8>, Vec<u32>)>) -> u64 {
|
||||
records.iter().fold(0, |acc, r| acc + check_record(r))
|
||||
}
|
||||
|
||||
pub fn sum_arrangements(duplicate: bool) -> u64 {
|
||||
let mut buffer = Vec::new();
|
||||
io::stdin().read_to_end(&mut buffer).unwrap();
|
||||
let lines = buffer.split(|c| *c == b'\n');
|
||||
let mut records: Vec<(Vec<u8>, Vec<u32>)> = Vec::new();
|
||||
for line in lines {
|
||||
if line.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut linesplit = line.split(|c| *c == b' ');
|
||||
let springs = linesplit.next().unwrap();
|
||||
let configs: Vec<_> = linesplit
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(|c| *c == b',')
|
||||
.map(|n| std::str::from_utf8(n).expect("").parse().expect(""))
|
||||
.collect();
|
||||
let spring_vec = if duplicate {
|
||||
let mut vec = Vec::new();
|
||||
for _ in 0..5 {
|
||||
vec.extend_from_slice(springs);
|
||||
vec.push(b'?');
|
||||
}
|
||||
vec.pop();
|
||||
vec
|
||||
} else {
|
||||
springs.to_vec()
|
||||
};
|
||||
let config_vec = if duplicate {
|
||||
let mut vec = Vec::new();
|
||||
for _ in 0..5 {
|
||||
vec.extend_from_slice(&configs);
|
||||
}
|
||||
vec
|
||||
} else {
|
||||
configs.to_vec()
|
||||
};
|
||||
records.push((spring_vec, config_vec));
|
||||
}
|
||||
|
||||
check_records(records)
|
||||
}
|
|
@ -3,6 +3,7 @@ use std::env;
|
|||
mod day1;
|
||||
mod day10;
|
||||
mod day11;
|
||||
mod day12;
|
||||
mod day2;
|
||||
mod day3;
|
||||
mod day4;
|
||||
|
@ -41,6 +42,8 @@ fn main() {
|
|||
"day10b" => println!("Contains: {}", day10::num_steps().1),
|
||||
"day11a" => println!("Sum: {}", day11::sum_lengths(1)),
|
||||
"day11b" => println!("Sum: {}", day11::sum_lengths(999999)),
|
||||
"day12a" => println!("Sum: {}", day12::sum_arrangements(false)),
|
||||
"day12b" => println!("Sum: {}", day12::sum_arrangements(true)),
|
||||
_ => println!("Unrecognized day: {}", args[1]),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue