feat: day 8

This commit is contained in:
Lucy 2024-12-11 11:20:28 +01:00
parent e01ba930ff
commit 1e9030960d
4 changed files with 216 additions and 5 deletions

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[features]
full = ["day1", "day2", "day3", "day4", "day5", "day6", "day7"]
full = ["day1", "day2", "day3", "day4", "day5", "day6", "day7", "day8"]
default = ["full"]
day1 = []
day2 = []
@ -13,6 +13,7 @@ day4 = []
day5 = []
day6 = []
day7 = []
day8 = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

12
inputs/day08/example.txt Normal file
View file

@ -0,0 +1,12 @@
............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............

188
src/day08.rs Normal file
View file

@ -0,0 +1,188 @@
#![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)
}
}

View file

@ -1,5 +1,8 @@
use std::{fmt::Display, fs::read_to_string, time::Instant};
use color_eyre::eyre;
use tracing_subscriber::EnvFilter;
#[cfg(feature = "day1")]
mod day01;
#[cfg(feature = "day2")]
@ -14,10 +17,14 @@ mod day05;
mod day06;
#[cfg(feature = "day7")]
mod day07;
#[cfg(feature = "day8")]
mod day08;
fn main() {
color_eyre::install().unwrap();
tracing_subscriber::fmt().init();
fn main() -> eyre::Result<()> {
color_eyre::install()?;
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
#[cfg(feature = "day1")]
solve_day(1, day01::pt1, day01::pt2);
#[cfg(feature = "day2")]
@ -32,6 +39,9 @@ fn main() {
solve_day(6, day06::pt1, day06::pt2);
#[cfg(feature = "day7")]
solve_day(7, day07::pt1, day07::pt2);
#[cfg(feature = "day8")]
solve_day(8, day08::pt1, day08::pt2);
Ok(())
}
fn solve_day<Fa, Fb, Ta, Tb>(day: u8, part_a: Fa, part_b: Fb)
@ -52,6 +62,6 @@ where
}
Err(_) => {
tracing::warn!("could not open ./inputs/day{day:02}/input.txt");
},
}
}
}