Compare commits

...

3 commits

Author SHA1 Message Date
f458030577 day 12 part 2 2023-12-15 13:18:24 -05:00
92b37dbfce day 12 part 1 2023-12-15 13:17:29 -05:00
68c0f3c3a3 day 12 part 1 (dirty) 2023-12-15 12:59:27 -05:00
3 changed files with 1110 additions and 201 deletions

View file

@ -1,10 +1,6 @@
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....
???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1

1140
input.txt

File diff suppressed because it is too large Load diff

View file

@ -1,65 +1,118 @@
use std::{cmp::max, collections::HashSet, io::stdin};
use std::{collections::HashMap, io::stdin};
use anyhow::{bail, Result};
use anyhow::Result;
fn main() -> Result<()> {
let mut grid = vec![];
let mut galaxies = HashSet::new();
let mut occupied_columns = HashSet::new();
let mut occupied_rows = HashSet::new();
let mut max_x = 0;
let mut max_y = 0;
for (y, line) in stdin().lines().map_while(Result::ok).enumerate() {
let cells: Vec<char> = line.chars().collect();
max_y = max(max_y, y);
for (x, c) in cells.iter().enumerate() {
max_x = max(max_x, x);
if *c == '#' {
galaxies.insert((x, y));
occupied_columns.insert(x);
occupied_rows.insert(y);
fn matches(conditions: &str, group: &str) -> bool {
for (g, c) in group.chars().zip(conditions.chars()) {
if c == '?' {
continue;
}
if g == c {
continue;
}
return false;
}
true
}
type Cache = HashMap<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>();
let positions = w - g.len() + 1;
let mut sum = 0;
for i in 0..positions {
if !matches(&conditions[i..], g) {
continue;
}
if conditions[..i].contains('#') {
continue;
}
let after = if (i + g.len()) < conditions.len() {
conditions.chars().nth(i + g.len()).unwrap()
} else {
'.'
};
if after == '#' {
continue;
}
if groups.len() == 1 {
if conditions[i + g.len()..].contains('#') {
continue;
}
sum += 1;
} else {
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;
}
}
grid.push(cells);
}
sum
}
let mut empty_columns: Vec<usize> = HashSet::from_iter(0..max_x)
.difference(&occupied_columns)
.copied()
.collect();
let mut empty_rows: Vec<usize> = HashSet::from_iter(0..max_y)
.difference(&occupied_rows)
.copied()
.collect();
empty_columns.sort();
empty_rows.sort();
let mut expanded_galaxies = HashSet::new();
let expansion = 1_000_000;
for (x, y) in galaxies.into_iter() {
let Err(col) = empty_columns.binary_search(&x) else {
bail!("x={x} found in empty columns");
};
let new_x = x + col * (expansion - 1);
let Err(row) = empty_rows.binary_search(&y) else {
bail!("y={y} found in empty rows");
};
let new_y = y + row * (expansion - 1);
expanded_galaxies.insert((new_x, new_y));
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));
}
let mut cache: Cache = Cache::new();
arrangements_inner(conditions, &group_strings, &mut cache)
}
fn main() -> Result<()> {
let mut sum = 0;
for a in expanded_galaxies.iter() {
for b in expanded_galaxies.iter() {
let dx = i64::abs(a.0 as i64 - b.0 as i64);
let dy = i64::abs(a.1 as i64 - b.1 as i64);
// println!("{a:?} -> {b:?} = {}", dx + dy);
sum += dx + dy;
}
for line in stdin().lines().map_while(Result::ok) {
let mut split = line.split_whitespace();
let conditions = split.next().unwrap();
let groups: Vec<usize> = split
.next()
.unwrap()
.split(',')
.map(str::parse)
.map_while(Result::ok)
.collect();
let conditions = [conditions].repeat(5).join("?");
let groups = groups.repeat(5);
let a = arrangements(&conditions, &groups);
sum += a;
}
sum /= 2;
println!("{sum}");
Ok(())
}
#[cfg(test)]
mod tests {}
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);
assert_eq!(arrangements("????#?#?..?#?", &[4, 1]), 2);
}
#[test]
fn test_matches() {
assert!(matches("?", "#"));
assert!(matches("?", "."));
assert!(matches("#", "#"));
assert!(matches(".", "."));
assert!(!matches("#", "."));
assert!(!matches(".", "#"));
}
}