add day 13

This commit is contained in:
timeshifter
2026-07-01 20:42:55 +02:00
parent 3aff343f90
commit 901ebbba71
3 changed files with 148 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
use std::{
collections::{HashSet, VecDeque},
vec,
};
#[cfg(debug_assertions)]
const INPUT: usize = 10;
#[cfg(not(debug_assertions))]
const INPUT: usize = 1362;
const MAX_X: usize = 100;
const MAX_Y: usize = 100;
fn main() {
let maze = generate_maze(INPUT);
let result = bfs(&maze, (1, 1), (31, 39));
println!("{result}");
}
#[allow(clippy::needless_range_loop)]
fn generate_maze(input: usize) -> Vec<Vec<WallOrSpace>> {
let mut result = vec![vec![WallOrSpace::default(); MAX_Y]; MAX_X];
for x in 0..MAX_X {
for y in 0..MAX_Y {
let equation = calculate_equation(x, y);
let sum = equation + input;
let binary = format!("{:b}", sum);
let ones = binary.chars().filter(|c| *c == '1').count();
if ones % 2 == 1 {
result[x][y] = WallOrSpace::Wall;
}
}
}
result
}
fn bfs(maze: &[Vec<WallOrSpace>], start: (usize, usize), goal: (usize, usize)) -> usize {
let mut queue = VecDeque::new();
let mut visited = HashSet::new();
visited.insert(start);
let mut reachable_in_50_steps = HashSet::new();
reachable_in_50_steps.insert(start);
queue.push_back((start, 0_usize));
while let Some(((xi, yi), distance)) = queue.pop_front() {
if (xi, yi) == goal {
println!("{}", reachable_in_50_steps.len());
return distance;
}
if distance <= 50 {
reachable_in_50_steps.insert((xi, yi));
}
for neighbor in get_valid_neighbors(maze, (xi, yi)) {
if !visited.contains(&neighbor) {
visited.insert(neighbor);
queue.push_back((neighbor, distance + 1));
}
}
}
panic!("goal unreachable");
}
fn get_valid_neighbors(
maze: &[Vec<WallOrSpace>],
(x, y): (usize, usize),
) -> impl Iterator<Item = (usize, usize)> {
let mut result = vec![];
if x == 0 && y == 0 {
result.push((x + 1, y));
result.push((x, y + 1));
} else if x == 0 && y != 0 {
result.push((x + 1, y));
result.push((x, y - 1));
result.push((x, y + 1));
} else if x != 0 && y == 0 {
result.push((x - 1, y));
result.push((x + 1, y));
result.push((x, y + 1));
} else {
// x != 0 && y != 0
result.push((x - 1, y));
result.push((x + 1, y));
result.push((x, y - 1));
result.push((x, y + 1));
}
result
.into_iter()
.filter(|(x, y)| *x < MAX_X && *y < MAX_Y)
.filter(|(x, y)| maze[*x][*y].is_space())
}
fn calculate_equation(x: usize, y: usize) -> usize {
x * x + 3 * x + 2 * x * y + y + y * y
}
#[derive(Clone, Debug, Default)]
enum WallOrSpace {
#[default]
Space,
Wall,
}
impl WallOrSpace {
fn is_space(&self) -> bool {
match self {
WallOrSpace::Space => true,
WallOrSpace::Wall => false,
}
}
}
#[allow(clippy::needless_range_loop, dead_code)]
fn print_maze(maze: &[Vec<WallOrSpace>]) {
for x in 0..MAX_X {
for y in 0..MAX_Y {
let c = match maze[x][y] {
WallOrSpace::Space => '.',
WallOrSpace::Wall => '#',
};
print!("{c}");
}
println!()
}
}