diff --git a/Day12/rust/Cargo.toml b/Day12/rust/Cargo.toml new file mode 100644 index 0000000..1ec6963 --- /dev/null +++ b/Day12/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/Day12/rust/src/main.rs b/Day12/rust/src/main.rs new file mode 100644 index 0000000..a425978 --- /dev/null +++ b/Day12/rust/src/main.rs @@ -0,0 +1,82 @@ +use std::fs; +use std::collections::HashMap; + +fn read_data(file_path: &str) -> Result, String> { + fs::read_to_string(file_path) + .map_err(|e| e.to_string()) + .map(|contents| contents.lines().map(String::from).collect()) +} + +fn unfold_record(record: &str) -> (String, Vec) { + let parts: Vec<&str> = record.split(' ').collect(); + let dots = parts[0].repeat(5).split("").collect::>().join("?"); + let blocks = parts[1].split(',').map(|x| x.parse::().unwrap()).collect::>(); + let unfolded_blocks = blocks.iter().flat_map(|&b| vec![b; 5]).collect(); + (dots, unfolded_blocks) +} + +fn count_arrangements(dots: &str, blocks: &[usize], i: usize, bi: usize, current: usize, memo: &mut HashMap<(usize, usize, usize), usize>) -> usize { + let key = (i, bi, current); + if let Some(&result) = memo.get(&key) { + return result; + } + + if i == dots.len() { + return if bi == blocks.len() && current == 0 { + 1 + } else { + 0 + }; + } + + let mut ans = 0; + let c = dots.chars().nth(i).unwrap(); + + if c == '.' || c == '?' { + if current == 0 { + ans += count_arrangements(dots, blocks, i + 1, bi, 0, memo); + } else if bi < blocks.len() && current == blocks[bi] { + ans += count_arrangements(dots, blocks, i + 1, bi + 1, 0, memo); + } + } + + if c == '#' || c == '?' { + if bi < blocks.len() && (current + 1 <= blocks[bi]) { + ans += count_arrangements(dots, blocks, i + 1, bi, current + 1, memo); + } + } + + memo.insert(key, ans); + ans +} + +fn solve_puzzle(lines: &[String]) -> usize { + lines.iter().fold(0, |acc, line| { + println!("Processing: {}", line); + let (dots, blocks) = unfold_record(line); + let line_result = count_arrangements(&dots, &blocks, 0, 0, 0, &mut HashMap::new()); + println!("Line result: {}", line_result); + acc + line_result + }) +} + +fn test_puzzle() -> Result<(), String> { + println!("Running tests..."); + let test_lines = read_data("../test.txt")?; + let test_result = solve_puzzle(&test_lines); + println!("Test result: {}", test_result); + assert_eq!(test_result, 525152, "Test failed!"); + println!("Test passed."); + Ok(()) +} + +fn main() -> Result<(), String> { + test_puzzle()?; + + let input_lines = read_data("../input.txt")?; + println!("Processing input data..."); + let result = solve_puzzle(&input_lines); + println!("Final result: {}", result); + + Ok(()) +}