solve Day12 with rust
This commit is contained in:
parent
6431902b14
commit
b80bbc27ce
@ -1,82 +1,98 @@
|
|||||||
use std::fs;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
fn read_data(file_path: &str) -> Result<Vec<String>, String> {
|
#[derive(Debug, Clone)]
|
||||||
fs::read_to_string(file_path)
|
struct Spring {
|
||||||
.map_err(|e| e.to_string())
|
field: Vec<char>,
|
||||||
.map(|contents| contents.lines().map(String::from).collect())
|
springs: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unfold_record(record: &str) -> (String, Vec<usize>) {
|
fn main() {
|
||||||
let parts: Vec<&str> = record.split(' ').collect();
|
match test_puzzle("../test.txt") {
|
||||||
let dots = parts[0].repeat(5).split("").collect::<Vec<&str>>().join("?");
|
Ok(_) => println!("Test passed."),
|
||||||
let blocks = parts[1].split(',').map(|x| x.parse::<usize>().unwrap()).collect::<Vec<usize>>();
|
Err(e) => println!("Test failed: {}", e),
|
||||||
let unfolded_blocks = blocks.iter().flat_map(|&b| vec![b; 5]).collect();
|
};
|
||||||
(dots, unfolded_blocks)
|
|
||||||
|
match run_puzzle("../input.txt") {
|
||||||
|
Ok(result) => println!("Final result: {}", result),
|
||||||
|
Err(e) => println!("Error: {}", e),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_arrangements(dots: &str, blocks: &[usize], i: usize, bi: usize, current: usize, memo: &mut HashMap<(usize, usize, usize), usize>) -> usize {
|
fn run_puzzle(file_path: &str) -> Result<usize, String> {
|
||||||
let key = (i, bi, current);
|
let input = fs::read_to_string(file_path).map_err(|e| e.to_string())?;
|
||||||
if let Some(&result) = memo.get(&key) {
|
let springs = parse(&input);
|
||||||
return result;
|
Ok(springs.iter().map(|s| s.clone().expand().arrangements()).sum())
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
fn test_puzzle(file_path: &str) -> Result<(), String> {
|
||||||
lines.iter().fold(0, |acc, line| {
|
let input = fs::read_to_string(file_path).map_err(|e| e.to_string())?;
|
||||||
println!("Processing: {}", line);
|
let springs = parse(&input);
|
||||||
let (dots, blocks) = unfold_record(line);
|
let result = springs.iter().map(|s| s.clone().expand().arrangements()).sum::<usize>();
|
||||||
let line_result = count_arrangements(&dots, &blocks, 0, 0, 0, &mut HashMap::new());
|
assert_eq!(result, 525152, "Test failed!");
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn parse(input: &str) -> Vec<Spring> {
|
||||||
test_puzzle()?;
|
input
|
||||||
|
.lines()
|
||||||
let input_lines = read_data("../input.txt")?;
|
.map(|line| {
|
||||||
println!("Processing input data...");
|
let (field, springs) = line.split_once(' ').unwrap();
|
||||||
let result = solve_puzzle(&input_lines);
|
let springs = springs.split(',').map(|s| s.parse().unwrap()).collect::<Vec<_>>();
|
||||||
println!("Final result: {}", result);
|
let mut field = field.chars().collect::<Vec<_>>();
|
||||||
|
field.push('.');
|
||||||
Ok(())
|
Spring { field, springs }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Spring {
|
||||||
|
fn arrangements(&self) -> usize {
|
||||||
|
fn count(
|
||||||
|
memo: &mut HashMap<(usize, usize, usize), usize>,
|
||||||
|
spring: &Spring,
|
||||||
|
pos: usize,
|
||||||
|
block: usize,
|
||||||
|
sequences: usize,
|
||||||
|
) -> usize {
|
||||||
|
if let Some(&res) = memo.get(&(pos, block, sequences)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = 0;
|
||||||
|
if pos == spring.field.len() {
|
||||||
|
res = (sequences == spring.springs.len()) as usize;
|
||||||
|
} else if spring.field[pos] == '#' {
|
||||||
|
res = count(memo, spring, pos + 1, block + 1, sequences)
|
||||||
|
} else if spring.field[pos] == '.' || sequences == spring.springs.len() {
|
||||||
|
if sequences < spring.springs.len() && block == spring.springs[sequences] {
|
||||||
|
res = count(memo, spring, pos + 1, 0, sequences + 1)
|
||||||
|
} else if block == 0 {
|
||||||
|
res = count(memo, spring, pos + 1, 0, sequences)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res += count(memo, spring, pos + 1, block + 1, sequences);
|
||||||
|
if block == spring.springs[sequences] {
|
||||||
|
res += count(memo, spring, pos + 1, 0, sequences + 1)
|
||||||
|
} else if block == 0 {
|
||||||
|
res += count(memo, spring, pos + 1, 0, sequences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memo.insert((pos, block, sequences), res);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
count(&mut HashMap::new(), self, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand(&self) -> Self {
|
||||||
|
let mut new_field = self.field.clone();
|
||||||
|
*new_field.last_mut().unwrap() = '?';
|
||||||
|
|
||||||
|
Self {
|
||||||
|
field: new_field.repeat(5),
|
||||||
|
springs: self.springs.repeat(5),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user