use std::collections::{HashMap, HashSet}; use nom::{ character::complete::{multispace1, not_line_ending}, error::VerboseError, multi::separated_list1, }; fn parse(input: &str) -> ((i32, i32), HashMap>) { let (input, parse_result) = separated_list1(multispace1::<&str, VerboseError<_>>, not_line_ending)(input).unwrap(); if !input.is_empty() { panic!("Parsing yields additional input"); } let mut result: HashMap> = HashMap::new(); let dim = (parse_result[0].len() as i32, parse_result.len() as i32 - 1); for (y, line) in parse_result.into_iter().enumerate() { for (x, c) in line.chars().enumerate() { if c != '.' && c != '\n' { match result.get_mut(&c) { None => { result.insert(c, vec![(x as i32, y as i32)]); } Some(v) => v.push((x as i32, y as i32)), } } } } (dim, result) } fn check_in_rectangle(point: (i32, i32), h: i32, w: i32) -> bool { point.0 >= 0 && point.1 >= 0 && point.0 < w && point.1 < h } fn solve_1(input: &str) -> usize { let (dim, antennae) = parse(input); let dim = (dim.0 as i32, dim.1 as i32); let mut result: HashSet<(i32, i32)> = HashSet::new(); for (_, v) in antennae.into_iter() { let l = v.len(); for i in 0..l { let a = v[i]; for j in i + 1..l { let b = v[j]; let dif = (a.0 - b.0, a.1 - b.1); if check_in_rectangle((a.0 + dif.0, a.1 + dif.1), dim.1, dim.0) { result.insert((a.0 + dif.0, a.1 + dif.1)); } if check_in_rectangle((b.0 - dif.0, b.1 - dif.1), dim.1, dim.0) { result.insert((b.0 - dif.0, b.1 - dif.1)); } } } } result.len() } fn solve_2(input: &str) -> usize { let (dim, antennae) = parse(input); let dim = (dim.0 as i32, dim.1 as i32); let mut result: HashSet<(i32, i32)> = HashSet::new(); for (_, v) in antennae.into_iter() { let l = v.len(); for i in 0..l { for j in i + 1..l { let mut a = v[i]; let mut b = v[j]; let dif = (a.0 - b.0, a.1 - b.1); while check_in_rectangle(a, dim.1, dim.0) { result.insert(a); a = (a.0 + dif.0, a.1 + dif.1); } while check_in_rectangle(b, dim.1, dim.0) { result.insert(b); b = (b.0 - dif.0, b.1 - dif.1); } } } } result.len() } fn main() { println!("Hello, this is Patrick!"); let input = include_str!("../input.txt"); let result_1 = solve_1(input); println!( "The number of unique locations with an antinode are {}", result_1 ); let result_2 = solve_2(input); println!( "The new number of unique locations with an antinode are {}", result_2 ); } #[cfg(test)] mod tests { use super::*; #[test] fn test_1() { let test_input = include_str!("../test.txt"); assert_eq!(solve_1(test_input), 14); } #[test] fn test_2() { let test_input = include_str!("../test.txt"); assert_eq!(solve_2(test_input), 34); } }