2024-12-19 17:12:39 +01:00
|
|
|
use advent_of_code::include_aoc;
|
2024-12-08 02:04:16 +01:00
|
|
|
use advent_of_code::{
|
|
|
|
strings::{convert_to_array, line_to_char},
|
2024-12-11 00:59:44 +01:00
|
|
|
Kartesian, KartesianDirection, MaximumFromMap, Table,
|
2024-12-08 02:04:16 +01:00
|
|
|
};
|
|
|
|
|
2024-12-19 17:12:39 +01:00
|
|
|
include_aoc!(2024, 04);
|
2024-12-04 13:22:39 +01:00
|
|
|
|
2024-12-08 02:04:16 +01:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
|
|
|
|
struct TextPos {
|
2024-12-11 00:59:44 +01:00
|
|
|
start: Kartesian<usize>,
|
|
|
|
end: Kartesian<usize>,
|
2024-12-04 13:22:39 +01:00
|
|
|
}
|
|
|
|
|
2024-12-08 02:04:16 +01:00
|
|
|
impl TextPos {
|
2024-12-11 00:59:44 +01:00
|
|
|
fn center(self) -> Kartesian<usize> {
|
|
|
|
(self.start + self.end) / 2
|
2024-12-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
2024-12-11 00:59:44 +01:00
|
|
|
found.len()
|
2024-12-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
|
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() {
|
2024-12-16 22:12:30 +01:00
|
|
|
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-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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();
|
2024-12-08 02:04:16 +01:00
|
|
|
let mut coords = Vec::new();
|
2024-12-11 00:59:44 +01:00
|
|
|
let mut start_point;
|
|
|
|
for row in 0..height {
|
2024-12-08 02:04:16 +01:00
|
|
|
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 {
|
2024-12-08 02:04:16 +01:00
|
|
|
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-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-12-11 00:59:44 +01:00
|
|
|
coords
|
2024-12-08 02:04:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2024-12-04 13:22:39 +01:00
|
|
|
}
|