use std::ops::Neg; #[allow(unused_variables)] #[allow(unused_imports)] use advent_of_code::{include_data, include_example}; use advent_of_code::{ matrix, strings::{convert_to_array, line_to_char}, }; include_example!(DATA 2024 04); #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] struct TextPos { startx: usize, starty: usize, endx: usize, endy: usize, length: usize, } #[inline] fn dist(a: (usize, usize), b: (usize, usize)) -> (i32, i32) { (a.0 as i32 - b.0 as i32, a.1 as i32 - b.1 as i32) } #[inline] fn dist_abs(a: (usize, usize), b: (usize, usize)) -> (usize, usize) { let t = dist(a, b); (t.0.abs() as usize, t.1.abs() as usize) } impl TextPos { const fn center(self) -> (usize, usize) { ( self.startx.saturating_add(self.endx).div_ceil(2), self.starty.saturating_add(self.endy).div_ceil(2), ) } fn crossing(self, other: &&Self) -> bool { if self.length != other.length && self.length != 3 { todo!() } if self.center() != other.center() { return false; } true } } #[test] fn test_crossing() { let cases = [ ( TextPos { startx: 0, starty: 0, endx: 2, endy: 2, length: 3, }, TextPos { startx: 0, starty: 0, endx: 2, endy: 2, length: 3, }, true, ), ( TextPos { startx: 1, starty: 0, endx: 1, endy: 2, length: 3, }, TextPos { startx: 0, starty: 1, endx: 2, endy: 1, length: 3, }, true, ), ( TextPos { startx: 0, starty: 0, endx: 2, endy: 0, length: 3, }, TextPos { startx: 1, starty: 0, endx: 2, endy: 0, length: 3, }, false, ), ]; for case in cases { assert_eq!(case.0.crossing(&&case.1), case.2) } } fn valid(x: usize, y: i32, max: usize) -> Option { let tmp = if y < 0 { x.checked_sub(y.neg() as usize) } else { x.checked_add(y as usize) }; if let Some(xi) = tmp { if xi < max { return Some(xi); } } None } fn validxy( x: usize, y: usize, modx: i32, mody: i32, heigth: usize, length: usize, ) -> Option<(usize, usize)> { if let Some(xi) = valid(x, modx, length) { if let Some(yi) = valid(y, mody, heigth) { return Some((xi, yi)); } } None } fn find_text(data: Vec>, length: usize, heigth: usize, text: &str) -> (usize, usize) { let first: char = text.chars().nth(0).unwrap(); let mut amount = 0; let mut found; let mut character; let mut chars; let mut coords = Vec::new(); let mut currentpos; for row in 0..heigth { for column in 0..length { let char = data[row][column]; if char != first { continue; } for (x, y) in matrix(false, true, true) { if x == y && y == 0 { continue; } found = 1; chars = text.chars(); chars.next(); loop { character = chars.next(); if character == None { amount += 1; currentpos = TextPos { startx: row, starty: column, endx: (row as i32 + x * found) as usize, endy: (column as i32 + y * found) as usize, length: text.len(), }; coords.push(currentpos); break; } if let Some((posmodx, posmody)) = validxy(row, column, x * found, y * found, length, heigth) { if data[posmodx][posmody] == character.unwrap() { found += 1; } else { break; } } else { break; } } } } } let mut xtexts = Vec::new(); for node in coords.clone() { for o in coords.iter().filter(|other| node.crossing(other)) { let other = *o; if node == other { continue; } let x = (node.min(other), node.max(other)); if !xtexts.contains(&x) { xtexts.push(x); } } } println!("{:?}", xtexts); (amount, xtexts.len()) } fn main() { let table = convert_to_array(DATA, line_to_char); let length = table[0].len(); let (amount, _) = find_text(table.clone(), length, table.len(), "XMAS"); println!("There are {} XMAS in text", amount); let (amount, amount_cross) = find_text(table.clone(), length, table.len(), "MAS"); println!( "There are {} MAS in text, are {} crossed", amount, amount_cross ); }