adventofcode/days/2024/04.rs

122 Zeilen
3,6 KiB
Rust

use advent_of_code::include_aoc;
use advent_of_code::{
strings::{convert_to_array, line_to_char},
2024-12-11 00:59:44 +01:00
Kartesian, KartesianDirection, MaximumFromMap, Table,
};
include_aoc!(2024, 04);
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
struct TextPos {
2024-12-11 00:59:44 +01:00
start: Kartesian<usize>,
end: Kartesian<usize>,
}
impl TextPos {
2024-12-11 00:59:44 +01:00
fn center(self) -> Kartesian<usize> {
(self.start + self.end) / 2
}
}
2024-12-11 00:59:44 +01:00
fn get_x(list: Vec<TextPos>) -> usize {
let mut found = Vec::<(TextPos, TextPos)>::new();
let (mut higher, mut lower);
for outer in list.clone() {
for inner in list.clone() {
if outer == inner {
continue;
}
higher = outer.max(inner);
lower = outer.min(inner);
if lower.center() == higher.center() {
let diff = lower.start.diff(higher.start).0;
if diff.x == 0 && diff.y == 2 || diff.y == 0 && diff.x == 2 {
let tuple = (lower, higher);
if !found.contains(&tuple) {
found.push((lower, higher));
}
}
}
}
}
2024-12-11 00:59:44 +01:00
found.len()
}
2024-12-11 00:59:44 +01:00
fn follow_text(data: &Table, start_point: Kartesian<usize>, direction: KartesianDirection, current_pos: Kartesian<usize>, chars: Vec<char>, list: &mut Vec<TextPos>) {
let mut iter = chars.iter().cloned();
match iter.next() {
None => list.push(TextPos {
start: start_point,
end: current_pos,
}),
2024-12-11 00:59:44 +01:00
Some(c) => match current_pos.move_dir_max(direction.vector_abs(), direction, Kartesian::maximum(data)) {
None => return,
Some(new) => {
if data[new.x][new.y] != c {
return;
}
follow_text(data, start_point, direction, new, iter.collect(), list)
},
},
}
}
2024-12-11 00:59:44 +01:00
fn find_text(data: Table, text: &str) -> Vec<TextPos> {
let length = data[0].len();
let height = data.len();
let mut iter = text.chars();
let first = iter.next().unwrap();
let chars: Vec<char> = iter.collect();
let mut coords = Vec::new();
2024-12-11 00:59:44 +01:00
let mut start_point;
for row in 0..height {
for column in 0..length {
2024-12-11 00:59:44 +01:00
start_point = Kartesian::new(row, column);
if data[start_point.x][start_point.y] != first {
continue;
}
2024-12-11 00:59:44 +01:00
for dir in KartesianDirection::iter(false, true, true) {
follow_text(&data, start_point, dir, start_point, chars.clone(), &mut coords);
}
}
}
2024-12-11 00:59:44 +01:00
coords
}
fn main() {
2024-12-11 00:59:44 +01:00
let mut coords;
let table = convert_to_array::<_, _, '\n'>(DATA, line_to_char);
coords = find_text(table.clone(), "XMAS");
println!("There are {} XMAS in text", coords.len());
coords = find_text(table.clone(), "MAS");
let amount_cross = get_x(coords.clone());
println!("There are {} MAS in text, are {} crossed", coords.len(), amount_cross);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_crossing() {
let cases = [
(
TextPos {
start: Kartesian::new(0, 1),
end: Kartesian::new(2, 1),
length: 3,
},
TextPos {
start: Kartesian::new(1, 0),
end: Kartesian::new(1, 2),
length: 3,
},
true,
),
];
for case in cases {
assert_eq!(case.0.crossing(&&case.1), case.2)
}
}
}