adventofcode/days/2024/06.rs

152 Zeilen
4,3 KiB
Rust

use advent_of_code::{
include_aoc,
strings::{convert_to_array, line_to_char},
KartesianDirection,
};
use advent_of_code::{Kartesian, Table};
use log::debug;
use num::Integer;
include_aoc!(2024, 06);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct DirectionalKartesian<T: Integer> {
x: T,
y: T,
dir: KartesianDirection,
}
impl<T: Integer> From<(Kartesian<T>, KartesianDirection)> for DirectionalKartesian<T> {
fn from(value: (Kartesian<T>, KartesianDirection)) -> Self {
DirectionalKartesian {
x: value.0.x,
y: value.0.y,
dir: value.1,
}
}
}
impl<T: Integer + Copy> Into<(Kartesian<T>, KartesianDirection)> for &DirectionalKartesian<T> {
fn into(self) -> (Kartesian<T>, KartesianDirection) {
(
Kartesian {
x: self.x,
y: self.y,
},
self.dir,
)
}
}
impl<T: Integer> DirectionalKartesian<T> {
fn kartesian(self) -> Kartesian<T> {
Kartesian::new(self.x, self.y)
}
}
fn find_guard(map: Table) -> Kartesian<i32> {
let mut position = Kartesian::default();
for line in map {
for char in line {
if char == '^' {
return position;
}
position.y += 1;
}
position.y = 0;
position.x += 1;
}
unreachable!()
}
fn get_path(map: Table) -> Vec<DirectionalKartesian<i32>> {
let mut position = (find_guard(map.clone()), KartesianDirection::Top);
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
debug!("Guard is on coordinate {}:{}", position.0.x + 1, position.0.y + 1);
let mut passed = Vec::new();
passed.push(position.into());
loop {
position.0 = match position.0.checked_add_max(position.1.vector().into(), maximum) {
None => {
debug!("Guard left the space after {} steps", passed.len());
return passed;
},
Some(pos) => pos,
};
if map[position.0.x as usize][position.0.y as usize] != '#' {
passed.push(position.into());
continue;
}
position.0 -= position.1.vector();
debug!("Guard turned right on {}:{}", position.0.x + 1, position.0.y + 1);
position.1 = position.1.clockwise(false);
}
}
fn solver1(input: &str) -> usize {
let map = convert_to_array::<_, _, '\n'>(input, line_to_char);
let mut path = get_path(map);
path.sort();
path.dedup_by_key(|p| (p.x, p.y));
path.len()
}
fn is_looping(_path: Vec<DirectionalKartesian<i32>>, _start_point: DirectionalKartesian<i32>) -> bool {
false
}
#[allow(unused_variables, unused_mut)]
fn solver2(input: &str) -> usize {
let map = convert_to_array::<_, _, '\n'>(input, line_to_char);
let maximum = Kartesian::new(map.len() as i32, map[0].len() as i32);
let mut path = get_path(map.clone());
let mut p = path.iter();
let mut looppoints = Vec::new();
let startpoint = p.next().unwrap().kartesian();
let mut currentpoint: (Kartesian<i32>, KartesianDirection);
for point in p {
if point.kartesian() == startpoint {
continue;
}
currentpoint = point.into();
currentpoint.1 = currentpoint.1.clockwise(false);
loop {
currentpoint.0 = match currentpoint.0.checked_add_max(currentpoint.1.vector(), maximum) {
None => break,
Some(p) => p,
};
if path.contains(&currentpoint.into()) {
looppoints.push(point.kartesian());
break;
}
if map[currentpoint.0.x as usize][currentpoint.0.y as usize] == '#' {
currentpoint.0 -= currentpoint.1.vector();
currentpoint.1 = currentpoint.1.clockwise(false)
}
}
}
looppoints.dedup();
looppoints.len()
}
fn main() {
println!("Guard left the space after walking through {} distinct positions", solver1(DATA));
println!("There are {} positions that are good for loops", solver2(DATA));
}
#[cfg(test)]
mod test {
use super::*;
include_aoc!(EXAMPLE, 2024, 06, true);
#[test]
fn test_solution_1() {
assert_eq!(solver1(EXAMPLE), 41);
}
#[test]
fn test_solution_2() {
assert_eq!(solver2(EXAMPLE), 6);
}
}