189 lines
6.5 KiB
Rust
189 lines
6.5 KiB
Rust
#![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::<Vec<_>>();
|
|
let dims = (input.lines().next().unwrap().len(), input.lines().count());
|
|
debug!("dims: {dims:?}");
|
|
let node_positions = char_positions
|
|
.iter()
|
|
.filter(|(c, _, _)| *c != '.')
|
|
.collect::<Vec<_>>();
|
|
let unique_nodes = node_positions
|
|
.iter()
|
|
.map(|(c, _, _)| *c)
|
|
.collect::<HashSet<_>>();
|
|
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::<Vec<_>>()
|
|
.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::<String>()
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.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::<Vec<_>>();
|
|
let dims = (input.lines().next().unwrap().len(), input.lines().count());
|
|
debug!("dims: {dims:?}");
|
|
let node_positions = char_positions
|
|
.iter()
|
|
.filter(|(c, _, _)| *c != '.')
|
|
.collect::<Vec<_>>();
|
|
let unique_nodes = node_positions
|
|
.iter()
|
|
.map(|(c, _, _)| *c)
|
|
.collect::<HashSet<_>>();
|
|
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::<Vec<_>>()
|
|
.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::<String>()
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.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)
|
|
}
|
|
}
|