Solved day 8

This commit is contained in:
2024-12-09 00:39:26 +01:00
parent 2080faf5de
commit c18e37d476
5 changed files with 245 additions and 3 deletions

50
input/day08.txt Normal file
View File

@@ -0,0 +1,50 @@
............0.......................Bn...........v
.........0.....................8.........P.....D..
........M...........Q..0..8...h.......P...........
......M.A......c...................n..............
.....C..................A.........................
.M.AC....................................v........
........C..........W...w....J........Q...........y
.....i..............0.....nW.......w.Zv...6.......
........c....................A.........Pm........D
.............t.........x..........P....y....m.....
........................w...x.......F....Z........
...............Q......x6.......S......Z..O.......J
..............o.u........x....6.....r.D..M........
............c...o........u...Y....................
.........i............9..............g............
.....................d..WC..8.........J.g.........
...........X.c...............d...........m........
....................9.dR...........m......y.......
.............o.....9.......Y.6.OS...n..........F..
......i..................a..Q...r.Y.............U.
.....N......X......u..Ot...a......j......7........
..........q..X......t.....uH.......j.r..S.7.......
..........l...t....K.......................J......
...............9..............OB..................
...l.R...q..............g.......Y.7..V.......S....
..........................a.D............V........
......R.5...v.....W.............KB............U...
........Kp..F.N...........2.....B..............U..
..............................d..........h........
...L...NX...l...R...w..........F...........7......
..q.L......5.........................j............
.q.............5.......g..4.......................
............p...................s2..............Z.
......L...p...........................s..I........
........N..............................H..........
............5......................2.......hV.....
.............3..........1.......f.a...V...........
.....K..................................Hz....j...
.............k.b..G................I.....U........
.............1......................h.............
...........p...........L.....s....4T..............
.b..................G....s.T......I...............
............................H...........T4........
...............lk.................T...............
..i........................1........Iz............
..............b...........1........G..............
....b..............G..............................
........3......k............f..............4......
3.............k.2.....................z...........
...........3......................z..f............

12
input/day08_example.txt Normal file
View File

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

139
src/day8.rs Normal file
View File

@@ -0,0 +1,139 @@
use std::collections::HashMap;
use itertools::Itertools;
use crate::{day_solver::DaySolver, util::{Coord, Grid}};
#[cfg(test)]
use crate::util::read_file;
pub struct Day8 {
map: Grid<char>
}
impl Day8 {
pub fn create(input: String) -> Self {
return Day8 {
map: Grid::parse(input, None)
}
}
fn get_antennas_per_frequency(&self) -> HashMap<char, Vec<Coord<usize>>> {
let mut frequency_antennas: HashMap<char, Vec<Coord<usize>>> = HashMap::new();
for y in 0..self.map.height() {
for x in 0..self.map.width {
let cur = self.map.get(x, y);
let pos: Coord<usize> = Coord::new(x, y);
if cur != &'.' {
if let Some(ant_pos) = frequency_antennas.get_mut(cur) {
ant_pos.push(pos);
} else {
frequency_antennas.insert(cur.to_owned(), vec![pos]);
}
}
}
}
frequency_antennas
}
fn find_antinodes(&self, antennas: &Vec<Coord<usize>>) -> Vec<Coord<usize>> {
let mut antinodes = Vec::new();
for a in antennas {
for b in antennas {
if a == b {
continue;
}
let mut a_signed = a.as_signed();
let dist = a_signed.sub(&b.as_signed());
antinodes.push(a.to_owned());
while let Ok(antinode) = TryInto::<Coord<usize>>::try_into(a_signed.add(&dist)) {
if self.map.in_bounds(antinode.x, antinode.y) {
antinodes.push(antinode);
} else {
break;
}
a_signed = antinode.as_signed()
}
}
}
antinodes
}
}
impl DaySolver for Day8 {
fn solve_part1(&mut self) -> String {
let frequency_antennas = self.get_antennas_per_frequency();
frequency_antennas.iter()
.flat_map(|(_, antennas)| {
antennas.iter().flat_map(|a|
antennas.iter()
.filter_map(|b| if b.to_owned() == a.to_owned() {
None
} else {
let a_signed = a.as_signed();
let dist = a_signed.sub(&b.as_signed());
Some(a_signed.add(&dist))
})
)
})
.filter_map::<Coord<usize>, _>(|c| c.try_into().ok())
.filter(|c| self.map.in_bounds(c.x, c.y))
.unique()
// .map(|c| { println!("{:?}", c); c })
.count().to_string()
}
fn solve_part2(&mut self) -> String {
let frequency_antennas = self.get_antennas_per_frequency();
let antinodes = frequency_antennas.iter()
.flat_map(|(_, antennas)| self.find_antinodes(antennas))
.unique()
.collect::<Vec<Coord<usize>>>();
// let mut full_map = self.map.clone();
// antinodes.iter().for_each(|n| full_map.set(n.x, n.y, '#'));
// full_map.print();
antinodes
.len().to_string()
}
}
#[test]
fn test_part1() {
let mut day = Day8::create(read_file("input/day08_example.txt"));
assert_eq!("14", day.solve_part1());
}
#[test]
fn test_part1_basic() {
let sample = "..........
..........
..........
....a.....
..........
.....a....
..........
..........
..........
..........";
let mut day = Day8::create(sample.to_string());
assert_eq!("2", day.solve_part1());
}
#[test]
fn test_part2() {
let mut day = Day8::create(read_file("input/day08_example.txt"));
assert_eq!("34", day.solve_part2());
}

View File

@@ -8,6 +8,7 @@ use crate::day4::Day4;
use crate::day5::Day5;
use crate::day6::Day6;
use crate::day7::Day7;
use crate::day8::Day8;
use crate::day_solver::DaySolver;
use crate::util::read_file;
@@ -20,6 +21,7 @@ mod day4;
mod day5;
mod day6;
mod day7;
mod day8;
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
@@ -98,7 +100,7 @@ fn build_day_solver(day: u8, input: String) -> Option<Box<dyn DaySolver>> {
5 => Some(Box::new(Day5::create(input))),
6 => Some(Box::new(Day6::create(input))),
7 => Some(Box::new(Day7::create(input))),
// 8 => Some(Box::new(Day8::create(input))),
8 => Some(Box::new(Day8::create(input))),
// 9 => Some(Box::new(Day9::create(input))),
// 10 => Some(Box::new(Day10::create(input))),
// 11 => Some(Box::new(Day11::create(input))),

View File

@@ -2,7 +2,7 @@ use std::fmt::Display;
use std::fs;
use itertools::Itertools;
use num::Integer;
use num::{CheckedSub, Integer};
pub fn read_file(filename: &str) -> String {
fs::read_to_string(filename)
@@ -148,10 +148,32 @@ impl<T> Coord<T> where T: Sized {
}
#[allow(dead_code)]
impl <T> Coord<T> where T: Integer + Copy {
impl <T> Coord<T> where T: Integer + Copy + CheckedSub {
pub fn manhattan_dist(&self, other: &Coord<T>) -> T {
self.x.max(other.x).sub(self.x.min(other.x)) + self.y.max(other.y).sub(self.y.min(other.y))
}
pub fn add(&self, other: &Coord<T>) -> Coord<T> {
Coord {
x: self.x + other.x,
y: self.y + other.y
}
}
pub fn sub(&self, other: &Coord<T>) -> Coord<T> {
Coord {
x: self.x - other.x,
y: self.y - other.y
}
}
pub fn checked_sub(&self, other: &Coord<T>) -> Option<Coord<T>> {
if let Some(x_res) = self.x.checked_sub(&other.x) {
if let Some(y_res) = self.y.checked_sub(&other.y) {
return Some(Coord::new(x_res, y_res))
}
}
None
}
}
#[allow(dead_code)]
@@ -196,4 +218,21 @@ impl Coord<usize> {
pub fn add_signed(&self, rhs: Coord<isize>) -> Coord<usize> {
Coord::new(self.x.wrapping_add_signed(rhs.x), self.y.wrapping_add_signed(rhs.y))
}
pub fn as_signed(&self) -> Coord<isize> {
Coord::new(self.x.try_into().unwrap(), self.y.try_into().unwrap())
}
}
impl TryFrom<Coord<isize>> for Coord<usize> {
fn try_from(value: Coord<isize>) -> Result<Self, Self::Error> {
if let Ok(x) = value.x.try_into() {
if let Ok(y) = value.y.try_into() {
return Ok(Coord::new(x, y))
}
}
Err("It no fit")
}
type Error = &'static str;
}