day 12 part 1

main
Andy Teijelo 2023-12-15 13:17:29 -05:00
parent 68c0f3c3a3
commit 92b37dbfce
1 changed files with 24 additions and 243 deletions

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, io::stdin, ops::Range};
use std::{collections::HashMap, io::stdin};
use anyhow::Result;
@ -15,95 +15,19 @@ fn matches(conditions: &str, group: &str) -> bool {
true
}
// fn arrangements3_inner(
// conditions: &str,
// start: usize,
// groups: &[usize],
// cache: &mut Cache,
// ranges: &mut Vec<Range<usize>>,
// ) -> i64 {
// // println!("arrangements3_inner({conditions:?}, {groups:?}, {ranges:?}");
// if groups.is_empty() {
// let mut s = String::new();
// for i in 0..conditions.len() {
// if ranges.iter().any(|r| r.contains(&i)) {
// s.push('#');
// } else {
// s.push('.');
// }
// }
// let mut m = true;
// for (c, s) in conditions.chars().zip(s.chars()) {
// if c == '?' {
// continue;
// }
// if c == s {
// continue;
// }
// m = false;
// }
// if m {
// return 1;
// }
// return 0;
// }
// // let mut start = ranges.last().unwrap_or(&(0..0usize)).end;
// // if start > 0 {
// // start += 1;
// // }
// let w = conditions.len() - start - groups.iter().skip(1).sum::<usize>();
// let g = groups[0];
// // println!("start={start} w={w} g={g}");
// if w < g {
// return 0;
// }
// let positions = w - g + 1;
// let mut matches = 0;
// for i in start..(start + positions) {
// ranges.push(i..(i + g));
// let new_start = i + g + 1;
// let hash_key = format!("{},{:?},{:?}", new_start, &groups[1..], ranges);
// if let Some(value) = cache.get(&hash_key) {
// println!("cache hit");
// matches += value;
// } else {
// // println!("cache miss");
// let a = arrangements3_inner(conditions, new_start, &groups[1..], cache, ranges);
// cache.insert(hash_key, a);
// // insert into cache here
// matches += a;
// }
// ranges.pop();
// }
// matches
// }
//
// type Cache = HashMap<String, i64>;
//
// fn arrangements3(conditions: &str, groups: &[usize]) -> i64 {
// let mut ranges = vec![];
// let mut cache: HashMap<String, i64> = HashMap::new();
// arrangements3_inner(conditions, 0, groups, &mut cache, &mut ranges)
// }
type Cache = HashMap<String, i64>;
fn arrangements2_inner(conditions: &str, groups: &[String]) -> i64 {
fn arrangements_inner(conditions: &str, groups: &[String], cache: &mut Cache) -> i64 {
let g = &groups[0];
let w = conditions.len() - groups.iter().skip(1).map(|s| s.len()).sum::<usize>();
// println!(
// "{}conditions={conditions} groups={groups:?} w={w} g={g}",
// " ".repeat(depth)
// );
let positions = w - g.len() + 1;
// println!("positions={positions}");
let mut sum = 0;
for i in 0..positions {
if !matches(&conditions[i..], g) {
// println!("{}i={i} no match", " ".repeat(depth));
continue;
}
if conditions[..i].contains('#') {
// println!("{}i={i} found a # somewhere before", " ".repeat(depth));
continue;
}
let after = if (i + g.len()) < conditions.len() {
@ -112,156 +36,40 @@ fn arrangements2_inner(conditions: &str, groups: &[String]) -> i64 {
'.'
};
if after == '#' {
// println!("{}i={i} found a # right after", " ".repeat(depth));
continue;
}
if groups.len() == 1 {
if conditions[i + g.len()..].contains('#') {
// println!(
// "{}i={i} last group, but there are unmatched '#'s after",
// " ".repeat(depth)
// );
continue;
}
// println!("{}i={i} last group, counting", " ".repeat(depth));
sum += 1;
} else {
// println!("{}i={i}:", " ".repeat(depth));
sum += arrangements2_inner(&conditions[i + g.len()..], &groups[1..]);
let cache_key = format!("{},{:?}", &conditions[i + g.len()..], &groups[1..]);
if let Some(v) = cache.get(&cache_key) {
sum += v;
} else {
let a = arrangements_inner(&conditions[i + g.len()..], &groups[1..], cache);
cache.insert(cache_key, a);
sum += a;
}
}
}
sum
}
fn arrangements2(conditions: &str, groups: &[usize]) -> i64 {
fn arrangements(conditions: &str, groups: &[usize]) -> i64 {
let mut group_strings = vec![];
group_strings.push("#".repeat(groups[0]).to_owned());
for g in groups.iter().skip(1) {
group_strings.push(".".to_owned() + &"#".to_owned().repeat(*g));
}
arrangements2_inner(conditions, &group_strings)
let mut cache: Cache = Cache::new();
arrangements_inner(conditions, &group_strings, &mut cache)
}
// fn arrangements_inner(conditions: &str, groups: &[usize], indent: usize) -> i64 {
// println!(
// "{}arrangements(conditions: {}, groups: {:?})",
// " ".repeat(indent),
// conditions,
// groups
// );
// if groups.is_empty() {
// return 0;
// }
//
// let g = groups[0];
//
// // the max width for the 1st group is the length of the conditions string
// // minus the minimum width of the rest of the groups
// // which would be the length of each group (i.e. each # char) plus 1 (i.e. the .)
// let max_width: usize = conditions.len() - (groups.iter().skip(1).map(|n| n + 1).sum::<usize>());
// println!(" {}g={g}", " ".repeat(indent));
// println!(" {}max_width={max_width}", " ".repeat(indent));
//
// // if max_width == 1 {
// // return 1;
// // }
//
// // the possible positions for the group would then be the width available
// // for it, minus its own width, plus 1
// //
// // ????.
// // ##...
// // .##..
// // ..##.
// // ...##
// let positions = max_width - g + 1;
//
// println!(" {}positions={positions}", " ".repeat(indent));
// let mut sum = 0;
// for i in 0..positions {
// let mut matches = true;
// for (j, c) in conditions.chars().take(max_width).enumerate() {
// if (i..(i + g)).contains(&j) {
// // inside the group, the conditions need to be # or ?
// if c == '.' {
// println!(
// " {}i={i} j={j} found a dot inside the group",
// " ".repeat(indent)
// );
// matches = false;
// break;
// }
// } else {
// // outside the group, the conditions need to be . or ?
// if c == '#' {
// println!(
// " {}i={i} j={j} found a # outside the group",
// " ".repeat(indent)
// );
// matches = false;
// break;
// }
// }
// }
// if !matches {
// println!(" {}i={i} no match", " ".repeat(indent));
// continue;
// }
// // if (conditions[i..(i + g)]).contains('.') {
// // println!(
// // " {}i={i} conditions[{i}..{}]({}) contains a dot",
// // " ".repeat(indent),
// // i + g,
// // &conditions[i..(i + g)]
// // );
// // continue;
// // }
// // if i + g >= conditions.len() {
// // println!(" {}i={i} # nothing left, counts", " ".repeat(indent));
// // // nothing left on the right
// // sum += 1; // count this arrangement
// // continue;
// // }
// // // after the group, there has to be a '.' or a '?'
// // if conditions.chars().nth(i + g) == Some('#') {
// // println!(" {}i={i} # found after", " ".repeat(indent));
// // continue;
// // }
// // // before the group, there has to be a '.' or a '?' or the beginning of the string
// // if i > 0 && conditions.chars().nth(i - 1) == Some('#') {
// // println!(" {}i={i} # found before", " ".repeat(indent));
// // continue;
// // }
// // // // after the group, there needs to be a dot, or the end of the string
// // // let valid = match conditions.get(i + g..i + g + 1) {
// // // Some(c) => c == ".",
// // // None => true,
// // // };
// // // if !valid {
// // // continue;
// // // }
// if groups.len() == 1 {
// println!(" {}i={i} counts", " ".repeat(indent));
// sum += 1;
// } else {
// let a = arrangements_inner(&conditions[(i + g + 1)..], &groups[1..], indent + 1);
// sum += a;
// println!(" {}returned {a}", " ".repeat(indent),);
// }
// }
// sum
// }
//
// fn arrangements(conditions: &str, groups: &[usize]) -> i64 {
// arrangements_inner(conditions, groups, 0)
// }
fn main() -> Result<()> {
// println!("{}", arrangements("???.###", &[1, 1, 3], 0));
// println!("{}", arrangements3(".??.?#??##???.", &[1, 6]));
let mut sum = 0;
for line in stdin().lines().map_while(Result::ok) {
// print!("{line} ");
let mut split = line.split_whitespace();
let conditions = split.next().unwrap();
let groups: Vec<usize> = split
@ -272,12 +80,7 @@ fn main() -> Result<()> {
.map_while(Result::ok)
.collect();
// let conditions = conditions.repeat(5);
// let groups = groups.repeat(5);
// println!("{conditions} {groups:?}");
let a = arrangements2(&conditions, &groups);
// println!("{a}");
let a = arrangements(conditions, &groups);
sum += a;
}
println!("{sum}");
@ -288,40 +91,18 @@ fn main() -> Result<()> {
mod tests {
use super::*;
// #[test]
// fn test_arrangements() {
// assert_eq!(arrangements(".??.?#??##???.", &[1, 6]), 5);
// assert_eq!(arrangements("???.###", &[1, 1, 3]), 1);
// assert_eq!(arrangements(".??..??...?##.", &[1, 1, 3]), 4);
// assert_eq!(arrangements("?#?#?#?#?#?#?#?", &[1, 3, 1, 6]), 1);
// assert_eq!(arrangements("????.#...#...", &[4, 1, 1]), 1);
// assert_eq!(arrangements("????.######..#####.", &[1, 6, 5]), 4);
// assert_eq!(arrangements("?###????????", &[3, 2, 1]), 10);
// }
#[test]
fn test_arrangements2() {
// assert_eq!(arrangements2(".??.?#??##???.", &[1, 6]), 5);
// assert_eq!(arrangements2("???.###", &[1, 1, 3]), 1);
// assert_eq!(arrangements2(".??..??...?##.", &[1, 1, 3]), 4);
// assert_eq!(arrangements2("?#?#?#?#?#?#?#?", &[1, 3, 1, 6]), 1);
// assert_eq!(arrangements2("????.#...#...", &[4, 1, 1]), 1);
// assert_eq!(arrangements2("????.######..#####.", &[1, 6, 5]), 4);
// assert_eq!(arrangements2("?###????????", &[3, 2, 1]), 10);
assert_eq!(arrangements2("????#?#?..?#?", &[4, 1]), 2);
fn test_arrangements() {
assert_eq!(arrangements(".??.?#??##???.", &[1, 6]), 5);
assert_eq!(arrangements("???.###", &[1, 1, 3]), 1);
assert_eq!(arrangements(".??..??...?##.", &[1, 1, 3]), 4);
assert_eq!(arrangements("?#?#?#?#?#?#?#?", &[1, 3, 1, 6]), 1);
assert_eq!(arrangements("????.#...#...", &[4, 1, 1]), 1);
assert_eq!(arrangements("????.######..#####.", &[1, 6, 5]), 4);
assert_eq!(arrangements("?###????????", &[3, 2, 1]), 10);
assert_eq!(arrangements("????#?#?..?#?", &[4, 1]), 2);
}
// #[test]
// fn test_arrangements3() {
// assert_eq!(arrangements3(".??.?#??##???.", &[1, 6]), 5);
// assert_eq!(arrangements2("???.###", &[1, 1, 3]), 1);
// assert_eq!(arrangements2(".??..??...?##.", &[1, 1, 3]), 4);
// assert_eq!(arrangements2("?#?#?#?#?#?#?#?", &[1, 3, 1, 6]), 1);
// assert_eq!(arrangements2("????.#...#...", &[4, 1, 1]), 1);
// assert_eq!(arrangements2("????.######..#####.", &[1, 6, 5]), 4);
// assert_eq!(arrangements2("?###????????", &[3, 2, 1]), 10);
// }
#[test]
fn test_matches() {
assert!(matches("?", "#"));