Zytkowski's Thought Dumpster

Advent of Code 2023 - Day 12

I'ts that time of year again, the Advent of Code! I'm completing the challenges this year using Rust 🦀 Day 12 had a tough part 1, but a tougher part 2.

I have not been able to complete part 2 yet (I really don't think brute forcing this one is viable). But I plan to get back to it once I learn what I deem necessary! 🙌

I'll be posting my solutions here, just to document how I'm solving each challenge, and I highly encourage you to check them out before reading my solutions!

Here's the Day 12 Challenge

BTW: Complete Part 1 to have access to Part 2 😉

Solution for Part 1

use std::fs::File;
use std::io::{Read, Result};
use std::path::Path;
use std::str::FromStr;

fn main() {
    let input_file_path = "path_to_input_file";
    let mut curr_sum = 0;
    let file = file_as_string(input_file_path)
        .unwrap_or_else(|_| panic!("Could not find input file {}", input_file_path));
    for line in file.split("\r\n") {
        let (combination_base, groups) = line.split_once(' ').unwrap();
        let groups : Vec<usize> = groups.split(',')
            .map(|c| usize::from_str(c).unwrap())
            .collect();
        curr_sum += sum_valid_combinations(combination_base, &groups);
    }
    println!("Sum of valid arrangements: {}", curr_sum)
}

fn sum_valid_combinations(combination: &str, groups: &[usize]) -> usize {
    match combination.chars().filter(|c| c == &'?').count() > 0 {
        true => {
            // Replace first occurrence of wildcard with broken spring
            let comb_a = combination.replacen('?', "#", 1);
            // Replace first occurrence of wildcard with working spring
            let comb_b = combination.replacen('?', ".", 1);
            sum_valid_combinations(&comb_a, groups) + sum_valid_combinations(&comb_b, groups)
        }
        false => {
            match combination_matches_groups(combination, groups) {
                true => 1,
                false => 0,
            }
        }
    }
}

fn combination_matches_groups(comb : &str, groups: &[usize]) -> bool {
    let mut new_comb = comb.to_string();
    new_comb = new_comb.trim_matches('.').parse().unwrap();
    while new_comb.contains("..") {
        new_comb = new_comb.replace("..",".")
    }
    let sections = new_comb.split('.').count();
    if sections != groups.len() {
        return false
    }
    for (idx, group) in new_comb.split('.').enumerate() {
        if group.len() != groups[idx] {
            return false;
        }
    }
    true
}

fn file_as_string<P: AsRef<Path>>(filename: P) -> Result<String> {
    let mut file = File::open(filename)?;
    let mut file_as_str = String::new();
    File::read_to_string(&mut file, &mut file_as_str)?;
    Ok(file_as_str)
}

Solution for Part 2

// I will do this. One day. :P