This commit is contained in:
2024-12-08 16:35:33 +01:00
parent 2a91587ae5
commit 0dec0bbf82
6 changed files with 301 additions and 0 deletions

20
y2024/src/bin/d8.rs Normal file
View File

@@ -0,0 +1,20 @@
use std::fs;
use y2024::days::d8;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/8_input.txt")).unwrap();
println!("{}", d8::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/8_input.txt")).unwrap();
println!("{}", d8::process_part2(&content));
}

227
y2024/src/days/d8.rs Normal file
View File

@@ -0,0 +1,227 @@
use itertools::Itertools;
use std::collections::{HashMap, HashSet};
pub fn process_part1(input: &str) -> usize {
let mut antennas_freq_pos = HashMap::new();
// group all antenna positions by frequency
let grid = input
.lines()
.map(|line| line.chars().collect_vec())
.collect_vec();
let width = grid[0].len();
let height = grid.len();
for (y, line) in input.lines().enumerate() {
for (x, chara) in line.chars().enumerate() {
if chara == '.' {
continue;
}
antennas_freq_pos
.entry(chara)
.and_modify(|positions: &mut Vec<(isize, isize)>| {
positions.push((x as isize, y as isize))
})
.or_insert(vec![(x as isize, y as isize)]);
}
}
// get all combinations of 2 antennas by their frequency
// and get_antinodes
let mut antinodes = HashSet::new();
for (_freq, positions) in antennas_freq_pos {
let pairs = positions.into_iter().combinations(2);
for pair in pairs {
let (antinode_a, antinode_b) = get_antinodes(pair[0], pair[1]);
if antinode_a.0 >= 0
&& antinode_a.0 < width as isize
&& antinode_a.1 >= 0
&& antinode_a.1 < height as isize
{
antinodes.insert(antinode_a);
}
if antinode_b.0 >= 0
&& antinode_b.0 < width as isize
&& antinode_b.1 >= 0
&& antinode_b.1 < height as isize
{
antinodes.insert(antinode_b);
}
}
}
let mut antinodes = antinodes.iter().collect_vec();
antinodes.sort();
antinodes.len()
}
fn get_antinodes(
antenna_a: (isize, isize),
antenna_b: (isize, isize),
) -> ((isize, isize), (isize, isize)) {
let vec2 = ((antenna_a.0 - antenna_b.0), (antenna_a.1 - antenna_b.1));
let antinode_a = {
let antinode_a = ((antenna_a.0 + vec2.0), (antenna_a.1 + vec2.1));
if antinode_a == antenna_b {
((antenna_a.0 - vec2.0), (antenna_a.1 - vec2.1))
} else {
antinode_a
}
};
let antinode_b = {
let antinode_b = ((antenna_b.0 + vec2.0), (antenna_b.1 + vec2.1));
if antinode_b == antenna_a {
((antenna_b.0 - vec2.0), (antenna_b.1 - vec2.1))
} else {
antinode_b
}
};
(antinode_a, antinode_b)
}
fn get_reasonant_antinodes(
antenna_a: (isize, isize),
antenna_b: (isize, isize),
width: isize,
height: isize,
) -> Vec<(isize, isize)> {
let mut antinodes = HashSet::new();
antinodes.insert(antenna_a);
antinodes.insert(antenna_b);
let vec2 = ((antenna_a.0 - antenna_b.0), (antenna_a.1 - antenna_b.1));
let (mut a, mut b) = (antenna_a, antenna_b);
loop {
let antinode_a = {
let antinode_a = ((a.0 + vec2.0), (a.1 + vec2.1));
if antinode_a == b {
((a.0 - vec2.0), (a.1 - vec2.1))
} else {
antinode_a
}
};
if antinode_a.0 >= 0 && antinode_a.0 < width && antinode_a.1 >= 0 && antinode_a.1 < height {
antinodes.insert(antinode_a);
} else {
break;
}
b = a;
a = antinode_a;
}
let (mut a, mut b) = (antenna_a, antenna_b);
loop {
let antinode_b = {
let antinode_b = ((b.0 + vec2.0), (b.1 + vec2.1));
if antinode_b == a {
((b.0 - vec2.0), (b.1 - vec2.1))
} else {
antinode_b
}
};
if antinode_b.0 >= 0 && antinode_b.0 < width && antinode_b.1 >= 0 && antinode_b.1 < height {
antinodes.insert(antinode_b);
} else {
break;
}
a = b;
b = antinode_b;
}
antinodes.into_iter().collect_vec()
}
pub fn process_part2(input: &str) -> usize {
let mut antennas_freq_pos = HashMap::new();
// group all antenna positions by frequency
let grid = input
.lines()
.map(|line| line.chars().collect_vec())
.collect_vec();
let width = grid[0].len();
let height = grid.len();
for (y, line) in input.lines().enumerate() {
for (x, chara) in line.chars().enumerate() {
if chara == '.' {
continue;
}
antennas_freq_pos
.entry(chara)
.and_modify(|positions: &mut Vec<(isize, isize)>| {
positions.push((x as isize, y as isize))
})
.or_insert(vec![(x as isize, y as isize)]);
}
}
// get all combinations of 2 antennas by their frequency
// and get_antinodes
let mut all_antinodes: HashSet<(isize, isize)> = HashSet::new();
for (_freq, positions) in antennas_freq_pos {
let pairs = positions.into_iter().combinations(2);
for pair in pairs {
let (a, b) = (pair[0], pair[1]);
let antinodes = get_reasonant_antinodes(a, b, width as isize, height as isize);
all_antinodes.extend(antinodes.iter());
}
}
let mut antinodes = all_antinodes.iter().collect_vec();
antinodes.sort();
antinodes.len()
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = "............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............";
#[test]
fn part1() {
let result = process_part1(INPUT);
assert_eq!(result, 14);
}
#[test]
fn test_get_antinodes_1() {
let antenna_a = (5, 2);
let antenna_b = (7, 3);
let (antinode_a, antinode_b) = get_antinodes(antenna_a, antenna_b);
assert_eq!(antinode_a, (3, 1));
assert_eq!(antinode_b, (9, 4));
}
#[test]
fn test_get_antinodes_2() {
let antenna_a = (5, 2);
let antenna_b = (8, 1);
let (antinode_a, antinode_b) = get_antinodes(antenna_a, antenna_b);
assert_eq!(antinode_a, (2, 3));
assert_eq!(antinode_b, (11, 0));
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 34);
}
#[test]
fn part2_simple() {
let input = "T.........
...T......
.T........
..........
..........
..........
..........
..........
..........
..........";
let result = process_part2(input);
assert_eq!(result, 9);
}
}

View File

@@ -11,3 +11,5 @@ pub mod d5;
pub mod d6;
pub mod d7;
pub mod d8;