Solved day 8
This commit is contained in:
50
input/day08.txt
Normal file
50
input/day08.txt
Normal 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
12
input/day08_example.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
............
|
||||
........0...
|
||||
.....0......
|
||||
.......0....
|
||||
....0.......
|
||||
......A.....
|
||||
............
|
||||
............
|
||||
........A...
|
||||
.........A..
|
||||
............
|
||||
............
|
||||
139
src/day8.rs
Normal file
139
src/day8.rs
Normal 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());
|
||||
}
|
||||
@@ -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))),
|
||||
|
||||
43
src/util.rs
43
src/util.rs
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user