y2024d8
This commit is contained in:
20
y2024/src/bin/d8.rs
Normal file
20
y2024/src/bin/d8.rs
Normal 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
227
y2024/src/days/d8.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,5 @@ pub mod d5;
|
||||
pub mod d6;
|
||||
|
||||
pub mod d7;
|
||||
|
||||
pub mod d8;
|
||||
|
||||
Reference in New Issue
Block a user