diff --git a/Cargo.lock b/Cargo.lock index 145033c..262c282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,7 @@ version = "0.1.0" dependencies = [ "ansi_term", "clap", + "itertools", "paste", "regex", "thiserror", @@ -126,6 +127,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "heck" version = "0.5.0" @@ -138,6 +145,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "memchr" version = "2.7.4" diff --git a/Cargo.toml b/Cargo.toml index 7d46e65..9bebc8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ [dependencies] ansi_term = "0.12" clap = { version = "4", features = ["derive"] } + itertools = "0.13" paste = "1" regex = "1" thiserror = "2" diff --git a/src/main.rs b/src/main.rs index 535bbc3..e78e69f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,7 @@ fn main() -> Result<()> { 5 => AocDayFiveSolution, 6 => AocDaySixSolution, 7 => AocDaySevenSolution, + 8 => AocDayEightSolution, }; Ok(()) diff --git a/src/solutions/day_4.rs b/src/solutions/day_4.rs index 141f205..1b0ea21 100644 --- a/src/solutions/day_4.rs +++ b/src/solutions/day_4.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, fs::read_to_string, path::Path}; use super::AocSolution; use crate::utils::{coord::Coord, Result}; -const DIRS: [Coord; 8] = [ +const DIRS: [Coord; 8] = [ Coord::new(1, 0), Coord::new(1, -1), Coord::new(0, -1), @@ -15,7 +15,7 @@ const DIRS: [Coord; 8] = [ ]; struct XmasGrid { - pub grid: HashMap, + pub grid: HashMap, char>, } impl XmasGrid { @@ -29,7 +29,7 @@ impl XmasGrid { } } - fn find_xmas(&self, pos: Coord) -> usize { + fn find_xmas(&self, pos: Coord) -> usize { let mut tmp = 0; for dir in DIRS { let mut found = true; @@ -51,7 +51,7 @@ impl XmasGrid { tmp } - fn find_x_mas(&self, pos: Coord) -> usize { + fn find_x_mas(&self, pos: Coord) -> usize { let (x, y) = (pos.x, pos.y); let tr = self.grid.get(&Coord::new(x + 1, y + 1)); diff --git a/src/solutions/day_6.rs b/src/solutions/day_6.rs index 79e076a..4605797 100644 --- a/src/solutions/day_6.rs +++ b/src/solutions/day_6.rs @@ -10,8 +10,8 @@ use crate::utils::{coord::Coord, direction::Direction, Result}; #[derive(Debug, Clone)] struct Guard { dir: Direction, - cur: Coord, - grid: HashMap, + cur: Coord, + grid: HashMap, bool>, } impl Guard { diff --git a/src/solutions/day_7.rs b/src/solutions/day_7.rs index e98311d..8a79b56 100644 --- a/src/solutions/day_7.rs +++ b/src/solutions/day_7.rs @@ -1,4 +1,4 @@ -use std::{fs::read_to_string, ops::Mul, path::Path}; +use std::{fs::read_to_string, path::Path}; use super::AocSolution; use crate::utils::Result; diff --git a/src/solutions/day_8.rs b/src/solutions/day_8.rs index 1ea9f0a..11881b3 100644 --- a/src/solutions/day_8.rs +++ b/src/solutions/day_8.rs @@ -1,8 +1,87 @@ -use std::{fs::read_to_string, path::Path}; +use std::{collections::HashMap, fs::read_to_string, path::Path}; + +use itertools::Itertools; use super::AocSolution; -use crate::utils::Result; +use crate::utils::{coord::Coord, Result}; +fn anticoord(a: Coord, b: Coord) -> (Coord, Coord) { + let delta = a - b; + (a + delta, b - delta) +} + +struct Map { + pub antennas: HashMap>>, + pub grid: HashMap, bool>, +} + +impl Map { + fn new(src: &str) -> Self { + let (antennas, grid) = src + .lines() + .zip(0..) + .flat_map(|(line, y)| { + line.chars() + .zip(0..) + .map(move |(ch, x)| (Coord::new(x, y), ch)) + }) + .fold( + (HashMap::new(), HashMap::new()), + |(mut antennas, mut map), (coord, ch)| { + if ch != '.' { + antennas.entry(ch).or_insert(Vec::new()).push(coord); + } + + map.insert(coord, false); + + (antennas, map) + }, + ); + + Self { antennas, grid } + } + + fn locations(&mut self) -> u64 { + for freq in self.antennas.values() { + freq.iter() + .tuple_combinations::<(_, _)>() + .map(|(&a, &b)| anticoord(a, b)) + .for_each(|(a, b)| { + if let Some(flag) = self.grid.get_mut(&a) { + *flag = true; + } + + if let Some(flag) = self.grid.get_mut(&b) { + *flag = true; + } + }); + } + + self.grid.values().filter(|&&x| x).count() as u64 + } + + fn resonance(&mut self) -> u64 { + for freq in self.antennas.values() { + freq.iter() + .permutations(2) + .map(|v| (v[0], v[1])) + .filter(|(a, b)| a.ne(b)) + .for_each(|(&a, &b)| { + let dist = b - a; + let mut anti = b; + + while let Some(flag) = self.grid.get_mut(&anti) { + *flag = true; + anti = anti + dist; + } + }); + } + + self.grid.values().filter(|&&x| x).count() as u64 + } +} + +#[derive(Clone, Copy)] pub struct AocDayEightSolution; impl AocSolution for AocDayEightSolution { @@ -11,15 +90,17 @@ impl AocSolution for AocDayEightSolution { fn get_input(&self, path: Option<&Path>) -> Result { Ok(match path { Some(p) => read_to_string(p)?, - None => read_to_string("./input/day_day_8.txt")?, + None => read_to_string("./input/day_8.txt")?, }) } fn part_one(&self, input: &str) -> Result { - todo!() + let mut map = Map::new(input); + Ok(map.locations()) } fn part_two(&self, input: &str) -> Result { - todo!() + let mut map = Map::new(input); + Ok(map.resonance()) } } diff --git a/src/utils/coord.rs b/src/utils/coord.rs index fe2f850..b2c5314 100644 --- a/src/utils/coord.rs +++ b/src/utils/coord.rs @@ -1,29 +1,41 @@ -use std::ops::Add; +use std::{ + fmt::Debug, + hash::Hash, + ops::{Add, Sub}, +}; -use super::direction::Direction; +use super::{direction::Direction, Unit}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Coord { - pub x: i16, - pub y: i16, +pub struct Coord { + pub x: U, + pub y: U, } -impl Coord { - pub const fn new(x: i16, y: i16) -> Self { +impl Coord { + pub const fn new(x: U, y: U) -> Self { Self { x, y } } } -impl Add for Coord { - type Output = Coord; +impl Add for Coord { + type Output = Coord; fn add(self, rhs: Self) -> Self::Output { Self::new(self.x + rhs.x, self.y + rhs.y) } } -impl Add for Coord { - type Output = Coord; +impl Sub for Coord { + type Output = Coord; + + fn sub(self, rhs: Self) -> Self::Output { + Self::new(self.x - rhs.x, self.y - rhs.y) + } +} + +impl Add for Coord { + type Output = Coord; fn add(self, rhs: Direction) -> Self::Output { let tmp = rhs.lookahead(); diff --git a/src/utils/direction.rs b/src/utils/direction.rs index f675704..6a81aca 100644 --- a/src/utils/direction.rs +++ b/src/utils/direction.rs @@ -1,6 +1,6 @@ use std::ops::{Neg, Not}; -use super::coord::Coord; +use super::{coord::Coord, Unit}; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum Direction { @@ -34,12 +34,12 @@ impl Direction { *self = !*self } - pub fn lookahead(&self) -> Coord { + pub fn lookahead(&self) -> Coord { match self { - Self::Up => Coord::new(0, -1), - Self::Right => Coord::new(1, 0), - Self::Down => Coord::new(0, 1), - Self::Left => Coord::new(-1, 0), + Self::Up => Coord::new(0.into(), (-1).into()), + Self::Right => Coord::new(1.into(), 0.into()), + Self::Down => Coord::new(0.into(), 1.into()), + Self::Left => Coord::new((-1).into(), 0.into()), } } } diff --git a/src/utils/macros.rs b/src/utils/macros.rs index 87b2851..94f746f 100644 --- a/src/utils/macros.rs +++ b/src/utils/macros.rs @@ -11,3 +11,12 @@ macro_rules! map_solution { } }; } + +#[macro_export] +macro_rules! impl_unit_for_type { + ($($type:ty),+ $(,)?) => { + $( + impl $crate::utils::Unit for $type {} + )+ + }; +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 287db50..f7453b7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,6 +4,9 @@ pub mod macros; pub mod coord; pub mod direction; +mod unit; +pub use unit::*; + pub type Result = std::result::Result; #[derive(thiserror::Error, Debug)] diff --git a/src/utils/unit.rs b/src/utils/unit.rs new file mode 100644 index 0000000..b4affa8 --- /dev/null +++ b/src/utils/unit.rs @@ -0,0 +1,12 @@ +use std::{ + fmt::Debug, + hash::Hash, + ops::{Add, Sub}, +}; + +pub trait Unit: + Debug + Clone + Copy + PartialEq + Eq + Hash + Add + Sub + From +{ +} + +impl_unit_for_type!(i8, i16, i32, i64, i128);