#![allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)] use std::collections::HashSet; use tracing::{debug, trace}; pub fn pt1(input: &str) -> usize { let char_positions = input .lines() .map(str::chars) .enumerate() .flat_map(|(y, line)| line.enumerate().map(move |(x, char)| (char, x, y))) .collect::>(); let dims = (input.lines().next().unwrap().len(), input.lines().count()); debug!("dims: {dims:?}"); let node_positions = char_positions .iter() .filter(|(c, _, _)| *c != '.') .collect::>(); let unique_nodes = node_positions .iter() .map(|(c, _, _)| *c) .collect::>(); let mut antinode_positions = HashSet::<(usize, usize)>::new(); for node in unique_nodes { let matching_node_positions = node_positions .iter() .filter(|(c, _, _)| *c == node) .collect::>() .into_iter(); for (_, node_x, node_y) in matching_node_positions.clone() { for (_, other_node_x, other_node_y) in matching_node_positions.clone() { trace!( "comparing ({node_x}, {node_y}) with ({other_node_x}, {other_node_y}): {:?}, {:?}", node_x.cmp(other_node_x), node_y.cmp(other_node_y) ); if node_x == other_node_x && node_y == other_node_y { continue; } let dx = *node_x as isize - *other_node_x as isize; let dy = *node_y as isize - *other_node_y as isize; let prev_x = *node_x as isize + dx; let prev_y = *node_y as isize + dy; let post_x = *other_node_x as isize - dx; let post_y = *other_node_y as isize - dy; if prev_x >= 0 && (prev_x as usize) < dims.0 && prev_y >= 0 && (prev_y as usize) < dims.1 { antinode_positions.insert((prev_x as usize, prev_y as usize)); } if post_x >= 0 && (post_x as usize) < dims.0 && post_y >= 0 && (post_y as usize) < dims.1 { antinode_positions.insert((post_x as usize, post_y as usize)); } } } debug!("antinodes for {node}: {antinode_positions:?}"); } let new_map = input .lines() .enumerate() .map(|(y, line)| { line.chars() .enumerate() .map(|(x, c)| { if c != '.' || !antinode_positions.contains(&(x, y)) { c } else { '#' } }) .collect::() }) .collect::>() .join("\n"); debug!("new Map: \n{new_map}"); antinode_positions.len() } // 225 is too high pub fn pt2(input: &str) -> usize { let char_positions = input .lines() .map(str::chars) .enumerate() .flat_map(|(y, line)| line.enumerate().map(move |(x, char)| (char, x, y))) .collect::>(); let dims = (input.lines().next().unwrap().len(), input.lines().count()); debug!("dims: {dims:?}"); let node_positions = char_positions .iter() .filter(|(c, _, _)| *c != '.') .collect::>(); let unique_nodes = node_positions .iter() .map(|(c, _, _)| *c) .collect::>(); let mut antinode_positions = HashSet::<(usize, usize)>::new(); for node in unique_nodes { let matching_node_positions = node_positions .iter() .filter(|(c, _, _)| *c == node) .collect::>() .into_iter(); for (_, node_x, node_y) in matching_node_positions.clone() { for (_, other_node_x, other_node_y) in matching_node_positions.clone() { trace!( "comparing ({node_x}, {node_y}) with ({other_node_x}, {other_node_y}): {:?}, {:?}", node_x.cmp(other_node_x), node_y.cmp(other_node_y) ); if node_x == other_node_x && node_y == other_node_y { continue; } let dx = *node_x as isize - *other_node_x as isize; let dy = *node_y as isize - *other_node_y as isize; let mut prev_x = *node_x as isize; let mut prev_y = *node_y as isize; while prev_x >= 0 && (prev_x as usize) < dims.0 && prev_y >= 0 && (prev_y as usize) < dims.1 { antinode_positions.insert((prev_x as usize, prev_y as usize)); prev_x += dx; prev_y += dy; } let mut post_x = *other_node_x as isize; let mut post_y = *other_node_y as isize; while post_x >= 0 && (post_x as usize) < dims.0 && post_y >= 0 && (post_y as usize) < dims.1 { antinode_positions.insert((post_x as usize, post_y as usize)); post_x -= dx; post_y -= dy; } } } debug!("antinodes for {node}: {antinode_positions:?}"); } let new_map = input .lines() .enumerate() .map(|(y, line)| { line.chars() .enumerate() .map(|(x, c)| { if c != '.' || !antinode_positions.contains(&(x, y)) { c } else { '#' } }) .collect::() }) .collect::>() .join("\n"); debug!("new Map: \n{new_map}"); antinode_positions.len() } #[cfg(test)] mod tests { use tracing_test::traced_test; use super::{pt1, pt2}; use std::fs::read_to_string; #[traced_test] #[test] pub fn test_pt1() { let input = read_to_string("./inputs/day08/example.txt").expect("Missing example.txt for day08"); assert_eq!(pt1(&input), 14) } #[traced_test] #[test] pub fn test_pt2() { let input = read_to_string("./inputs/day08/example.txt").expect("Missing example.txt for day08"); assert_eq!(pt2(&input), 34) } }