From 8e5ea0f3af999ef0e66bbb008427fc595bf2a072 Mon Sep 17 00:00:00 2001 From: Timothy Quilling Date: Sun, 8 Dec 2024 14:28:18 -0500 Subject: [PATCH] add 2024 day8 in rust --- Cargo.toml | 4 ++ src/2024/day8/rust/mod.rs | 137 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 src/2024/day8/rust/mod.rs diff --git a/Cargo.toml b/Cargo.toml index d8cac80..c6e94b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,10 @@ path = "src/2024/day6/rust/mod.rs" name = "2024_day7" path = "src/2024/day7/rust/mod.rs" +[[bin]] +name = "2024_day8" +path = "src/2024/day8/rust/mod.rs" + [lints.rust] unsafe_code = "forbid" diff --git a/src/2024/day8/rust/mod.rs b/src/2024/day8/rust/mod.rs new file mode 100644 index 0000000..b67e830 --- /dev/null +++ b/src/2024/day8/rust/mod.rs @@ -0,0 +1,137 @@ +use std::collections::{HashMap, HashSet}; + +#[derive(Debug)] +struct Antenna { + frequency: char, + x: usize, + y: usize, +} + +#[derive(Debug)] +struct Map { + width: usize, + height: usize, + antennas: HashMap>, + antinodes: HashSet<(usize, usize)>, +} + +fn parse_input(input: &str) -> Map { + let mut antennas: HashMap> = HashMap::new(); + let lines: Vec<&str> = input.lines().collect(); + let (width, height) = (lines[0].len(), lines.len()); + + for (y, line) in lines.iter().enumerate() { + for (x, frequency) in line.chars().enumerate() { + if frequency.is_alphanumeric() { + antennas.entry(frequency).or_default().push(Antenna { frequency, x, y }); + } + } + } + + Map { width, height, antennas, antinodes: HashSet::new() } +} + +fn find_antinodes(map: &mut Map, is_part_b: bool) { + for frequency in map.antennas.keys() { + if let Some(antennas) = map.antennas.get(frequency) { + for (i, antenna1) in antennas.iter().enumerate() { + for antenna2 in &antennas[i + 1..] { + // let's do some geometry I guess + if is_part_b { + let (dx, dy) = (antenna2.x as i32 - antenna1.x as i32, antenna2.y as i32 - antenna1.y as i32); + let directions = [(antenna1, dx, dy), (antenna2, -dx, -dy)]; + + for (antenna, dx, dy) in &directions { + let (mut x, mut y) = (antenna.x as i32, antenna.y as i32); + while (0..map.width as i32).contains(&x) && (0..map.height as i32).contains(&y) { + map.antinodes.insert((x as usize, y as usize)); + x += dx; + y += dy; + } + } + } + + let offsets = [ + ( + antenna1.x as i32 - (antenna2.x as i32 - antenna1.x as i32), + antenna1.y as i32 - (antenna2.y as i32 - antenna1.y as i32), + ), + ( + antenna2.x as i32 + (antenna2.x as i32 - antenna1.x as i32), + antenna2.y as i32 + (antenna2.y as i32 - antenna1.y as i32), + ), + ]; + + for &(x, y) in &offsets { + if (0..map.width as i32).contains(&x) && (0..map.height as i32).contains(&y) { + map.antinodes.insert((x as usize, y as usize)); + } + } + } + } + } + } +} + +fn print_map(map: &Map) { + println!("Map:"); + for y in 0..map.height { + for x in 0..map.width { + let symbol = map.antennas.values().flatten().find(|a| a.x == x && a.y == y).map_or_else(|| if map.antinodes.contains(&(x, y)) { '#' } else { '.' }, |antenna| antenna.frequency); + print!("{}", symbol); + } + println!(); + } +} + +pub fn part_a(input: &str) -> i32 { + let mut map = parse_input(input); + print_map(&map); + find_antinodes(&mut map, false); + print_map(&map); + map.antinodes.len() as i32 +} + +pub fn part_b(input: &str) -> i32 { + let mut map = parse_input(input); + print_map(&map); + find_antinodes(&mut map, true); + print_map(&map); + map.antinodes.len() as i32 +} + +pub fn main() { + let input = include_str!("../input.txt"); + let example_input = include_str!("../input_example.txt"); + // let example_input_b = include_str!("../input_example_b.txt"); + let day: u8 = 8; + println!("Day {} Example Part A: {}", day, part_a(example_input)); + println!("Day {} Part A: {}", day, part_a(input)); + println!("Day {} Example Part B: {}", day, part_b(example_input)); + println!("Day {} Part B: {}", day, part_b(input)); +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_part_a_example() { + let example_input = include_str!("../input_example.txt"); + assert_eq!(part_a(example_input), 14); + } + #[test] + fn test_part_a() { + let input = include_str!("../input.txt"); + assert_eq!(part_a(input), 400); + } + #[test] + fn test_part_b_example() { + let example_input_b = include_str!("../input_example.txt"); + assert_eq!(part_b(example_input_b), 34); + } + #[test] + fn test_part_b() { + let input = include_str!("../input.txt"); + assert_eq!(part_b(input), 1280); + } +} -- 2.51.2