This commit is contained in:
2024-12-07 12:53:06 +01:00
parent a8ea67154b
commit e0663cce26
4 changed files with 165 additions and 0 deletions

2
2024/day6/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
target
input.txt

7
2024/day6/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day6"
version = "0.1.0"

6
2024/day6/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "day6"
version = "0.1.0"
edition = "2021"
[dependencies]

150
2024/day6/src/main.rs Normal file
View File

@@ -0,0 +1,150 @@
use std::collections::{HashMap, HashSet};
use std::fs;
use std::time::Instant;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
struct Point {
row: i32,
col: i32,
}
impl Point {
fn new(row: i32, col: i32) -> Self {
Self { row, col }
}
fn from(point: &Point, dir: &Point) -> Self {
Self {
row: point.row + dir.row,
col: point.col + dir.col,
}
}
fn is_in_map(&self, map: &[&[u8]]) -> bool {
!(self.col >= map[0].len() as i32
|| self.row >= map.len() as i32
|| self.col < 0
|| self.row < 0)
}
fn is_in_map_str(&self, map: &[String]) -> bool {
!(self.col >= map[0].len() as i32
|| self.row >= map.len() as i32
|| self.col < 0
|| self.row < 0)
}
}
const DIRECTION: [Point; 4] = [
Point { row: 1, col: 0 },
Point { row: 0, col: -1 },
Point { row: -1, col: 0 },
Point { row: 0, col: 1 },
];
fn main() {
let file = fs::read_to_string("./input.txt").unwrap();
let mut map: Vec<&[u8]> = Vec::new();
let mut map2: Vec<String> = Vec::new();
let mut start = Point::new(0, 0);
for (line_idx, line) in file.lines().enumerate() {
map.push(line.as_bytes());
map2.push(line.to_string());
for (idx, c) in line.chars().enumerate() {
if c == '^' {
start.row = line_idx as i32;
start.col = idx as i32;
}
}
}
let start_time = Instant::now();
println!("Solution 1: {}", puzzle1(map.clone(), start));
let end = Instant::now() - start_time;
println!("Solution 1 time: {}", end.as_micros());
let start_time = Instant::now();
println!("Solution 2: {}", puzzle2(map2, start));
let end = Instant::now() - start_time;
println!("Solution 2 time: {}", end.as_micros());
}
fn puzzle1(map: Vec<&[u8]>, start: Point) -> usize {
let mut visited = HashSet::new();
visited.insert(start);
let mut current = start;
let mut dir = 2;
loop {
let next = Point::from(&current, &DIRECTION[dir]);
if !next.is_in_map(&map) {
break;
}
if map[next.row as usize][next.col as usize] != b'#' {
visited.insert(next);
current = next;
} else {
dir = (dir + 1) % 4;
}
}
visited.len()
}
fn puzzle2(map: Vec<String>, start: Point) -> usize {
let mut map = map;
let visited = HashMap::new();
let mut positions = HashSet::new();
puzzle2_rec(start, 2, &mut map, visited, &mut positions, false);
positions.len()
}
fn puzzle2_rec(
mut current: Point,
mut dir: usize,
map: &mut Vec<String>,
mut visited: HashMap<Point, [bool; 4]>,
positions: &mut HashSet<Point>,
placed: bool,
) -> bool {
while current.is_in_map_str(map) {
visited
.entry(current)
.or_insert([false, false, false, false]);
if visited[&current][dir] && placed {
return true;
}
let next = Point::from(&current, &DIRECTION[dir]);
if !next.is_in_map_str(map) {
return false;
}
if map[next.row as usize].as_bytes()[next.col as usize] == b'#' {
dir = (dir + 1) % 4;
} else {
if !placed && !visited.contains_key(&next) {
let c = map[next.row as usize]
.chars()
.nth(next.col as usize)
.unwrap();
map[next.row as usize].replace_range(next.col as usize..=next.col as usize, "#");
if puzzle2_rec(
current,
(dir + 1) % 4,
map,
visited.clone(),
positions,
true,
) {
positions.insert(next);
}
map[next.row as usize]
.replace_range(next.col as usize..=next.col as usize, &c.to_string());
}
visited.get_mut(&current).unwrap()[dir] = true;
current = next;
}
}
false
}