use advent_of_code::{ strings::{convert_to_array, parsenumber}, Kartesian, Velocity, KD, }; use advent_of_code_macros::include_aoc; include_aoc!(2024, 14); fn parse_robot(line: &str) -> (Kartesian, Velocity) { let mut dir = KD::None; let mut x = 0; let mut y = 0; let mut position = Kartesian::default(); for part in line.splitn(2, ' ') { match part.get(0..2).unwrap_or("") { "p=" => { let (y, x) = part.get(2..).unwrap().split_once(',').unwrap(); position.x = parsenumber(x); position.y = parsenumber(y); }, "v=" => { let (ys, xs) = part.get(2..).unwrap().split_once(',').unwrap(); x = parsenumber(xs); y = parsenumber(ys); dir = if xs.get(0..1).unwrap() == "-" && x != 0 { dir.up() } else if x > 0 { dir.down() } else { dir }; dir = if ys.get(0..1).unwrap() == "-" && y != 0 { dir.left() } else if x > 0 { dir.right() } else { dir }; }, _ => {}, } } (position, Velocity::new(x, y, dir)) } fn get_end_start(v: u32) -> (u32, u32) { match v % 2 { 0 => (v / 2, v / 2), 1 => ((v - 1) / 2 - 1, (v + 1) / 2), _ => unreachable!(), } } fn calc_safety(coords: Vec>, space: Kartesian) -> (u32, u32, u32, u32) { let mut robots = (0, 0, 0, 0); let (x_end, x_start) = get_end_start(space.x); let (y_end, y_start) = get_end_start(space.y); for robot in coords { if robot.x <= x_end && robot.y <= y_end { robots.0 += 1; } else if robot.x <= x_end && robot.y >= y_start { robots.1 += 1 } else if robot.x >= x_start && robot.y <= y_end { robots.2 += 1 } else if robot.x >= x_start && robot.y >= y_start { robots.3 += 1 } else { println!("Robot outside of quarts {}:", robot); println!("1. {}..={}:{}..={}", 0, x_end, 0, y_end); println!("2. {}..={}:{}..={}", 0, x_end, y_start, space.y - 1); println!("3. {}..={}:{}..={}", x_start, space.x - 1, 0, y_end); println!("4. {}..={}:{}..={}", x_start, space.x - 1, y_start, space.y - 1); } } println!("Robot in quarts: {}, {}, {}, {}", robots.0, robots.1, robots.2, robots.3); robots } fn calc_final(r: (u32, u32, u32, u32)) -> u32 { r.0 * r.1 * r.2 * r.3 } fn main() { const SPACE: Kartesian = Kartesian::new(103, 101); let mut target_coords = Vec::new(); let robots = convert_to_array::<_, _, '\n'>(DATA, parse_robot); for (mut position, velocity) in robots { for _i in 0..100 { position = position.wrapping_move_velocity(velocity, SPACE); } target_coords.push(position); } println!("{:?}", target_coords); println!("Safety Factor: {}", calc_final(calc_safety(target_coords, SPACE))); } #[cfg(test)] mod test { use super::*; #[test] fn test_start_end() { assert_eq!(get_end_start(7), (2, 4)) } #[test] fn test_safety() { let positions = vec![ Kartesian { x: 5, y: 3, }, Kartesian { x: 4, y: 5, }, Kartesian { x: 0, y: 9, }, Kartesian { x: 5, y: 4, }, Kartesian { x: 6, y: 1, }, Kartesian { x: 3, y: 1, }, Kartesian { x: 0, y: 6, }, Kartesian { x: 3, y: 2, }, Kartesian { x: 2, y: 0, }, Kartesian { x: 0, y: 6, }, Kartesian { x: 5, y: 4, }, Kartesian { x: 6, y: 6, }, ]; assert_eq!(calc_safety(positions, Kartesian::new(7, 11)), (1, 3, 4, 1)); } }