Geen ongedefinieerd gedrag, enkel vergeten dat een plant onderdeel kan zijn van verschillende eigen hekkies
This commit is contained in:
193
advent_of_code/2024/12/src/main.rs
Normal file
193
advent_of_code/2024/12/src/main.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
fn parse(input: &str) -> HashMap<(i64, i64), char> {
|
||||
let mut result = HashMap::new();
|
||||
for (j, l) in input.lines().enumerate() {
|
||||
for (i, c) in l.chars().enumerate() {
|
||||
result.insert((i as i64, j as i64), c);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn solve_1(input: &str) -> i64 {
|
||||
let original_map = parse(input);
|
||||
let mut visited: HashSet<(i64, i64)> = HashSet::new();
|
||||
let mut result = 0;
|
||||
|
||||
for (&(x, y), plant) in original_map.iter() {
|
||||
if !visited.contains(&(x, y)) {
|
||||
let mut stack = vec![(x, y)];
|
||||
let mut area = 0;
|
||||
let mut perimeter = 0;
|
||||
visited.insert((x, y));
|
||||
|
||||
while !stack.is_empty() {
|
||||
let cur = stack.pop().unwrap_or_default();
|
||||
|
||||
area += 1;
|
||||
|
||||
let up = (cur.0, cur.1 - 1);
|
||||
let right = (cur.0 + 1, cur.1);
|
||||
let down = (cur.0, cur.1 + 1);
|
||||
let left = (cur.0 - 1, cur.1);
|
||||
|
||||
let candidates = vec![up, right, down, left];
|
||||
|
||||
for candidate in candidates {
|
||||
if let Some(p) = original_map.get(&candidate) {
|
||||
if p == plant {
|
||||
if !visited.contains(&candidate) {
|
||||
stack.push(candidate);
|
||||
visited.insert(candidate);
|
||||
}
|
||||
} else {
|
||||
perimeter += 1;
|
||||
}
|
||||
} else {
|
||||
perimeter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result += area * perimeter;
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn turn(dir: (i64, i64)) -> (i64, i64) {
|
||||
match dir {
|
||||
(0, -1) => (1, 0),
|
||||
(1, 0) => (0, 1),
|
||||
(0, 1) => (-1, 0),
|
||||
(-1, 0) => (0, -1),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn rev_turn(dir: (i64, i64)) -> (i64, i64) {
|
||||
turn(turn(turn(dir)))
|
||||
}
|
||||
|
||||
fn solve_2(input: &str) -> u64 {
|
||||
let original_map = parse(input);
|
||||
let mut visited: HashSet<(i64, i64)> = HashSet::new();
|
||||
let mut result = 0;
|
||||
|
||||
for (&(x, y), plant) in original_map.iter() {
|
||||
if !visited.contains(&(x, y)) {
|
||||
let mut stack = vec![(x, y)];
|
||||
let mut area = 0;
|
||||
visited.insert((x, y));
|
||||
let mut edges = HashSet::new();
|
||||
|
||||
while !stack.is_empty() {
|
||||
let cur = stack.pop().unwrap_or_default();
|
||||
|
||||
area += 1;
|
||||
|
||||
let up = (0, -1);
|
||||
let right = (1, 0);
|
||||
let down = (0, 1);
|
||||
let left = (-1, 0);
|
||||
let candidates = vec![up, right, down, left];
|
||||
|
||||
for candidate in candidates {
|
||||
let cand_coord = (cur.0 + candidate.0, cur.1 + candidate.1);
|
||||
|
||||
if let Some(p) = original_map.get(&cand_coord) {
|
||||
if p == plant {
|
||||
if !visited.contains(&cand_coord) {
|
||||
stack.push(cand_coord);
|
||||
visited.insert(cand_coord);
|
||||
}
|
||||
} else {
|
||||
edges.insert((cur, candidate));
|
||||
}
|
||||
} else {
|
||||
edges.insert((cur, candidate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut sides = 0;
|
||||
|
||||
while edges.len() > 0 {
|
||||
let start_edge = edges.iter().next().unwrap().to_owned();
|
||||
|
||||
let edge_side = start_edge.1;
|
||||
|
||||
let start_dir = turn(edge_side);
|
||||
let mut dir = start_dir.clone();
|
||||
let mut cur_edge = start_edge.clone().0;
|
||||
let mut visited_edges_dir: HashSet<((i64, i64), (i64, i64))> = HashSet::new();
|
||||
|
||||
while !visited_edges_dir.contains(&(start_edge.0, start_dir)) {
|
||||
let next = (cur_edge.0 + dir.0, cur_edge.1 + dir.1);
|
||||
|
||||
if let Some(p) = original_map.get(&next) {
|
||||
if p == plant {
|
||||
cur_edge = next;
|
||||
|
||||
let left = rev_turn(dir);
|
||||
let left_edge = (cur_edge.0 + left.0, cur_edge.1 + left.1);
|
||||
|
||||
if let Some(p2) = original_map.get(&left_edge) {
|
||||
if p2 == plant {
|
||||
dir = left;
|
||||
cur_edge = left_edge;
|
||||
sides += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dir = turn(dir);
|
||||
sides += 1;
|
||||
}
|
||||
} else {
|
||||
dir = turn(dir);
|
||||
sides += 1;
|
||||
}
|
||||
|
||||
edges.remove(&(cur_edge, rev_turn(dir)));
|
||||
visited_edges_dir.insert((cur_edge, dir));
|
||||
}
|
||||
}
|
||||
|
||||
result += area * sides;
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, this is Patrick!");
|
||||
|
||||
let input = include_str!("../input.txt");
|
||||
|
||||
let result_1 = solve_1(input);
|
||||
println!("The total price of all fencing is {}", result_1);
|
||||
|
||||
let result_2 = solve_2(input);
|
||||
println!("The new total price of all fencing is {}", result_2);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let test_input = include_str!("../test.txt");
|
||||
assert_eq!(solve_1(test_input), 1930);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let test_input = include_str!("../test.txt");
|
||||
assert_eq!(solve_2(test_input), 1206);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user