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::day5::Day5;
|
||||||
use crate::day6::Day6;
|
use crate::day6::Day6;
|
||||||
use crate::day7::Day7;
|
use crate::day7::Day7;
|
||||||
|
use crate::day8::Day8;
|
||||||
use crate::day_solver::DaySolver;
|
use crate::day_solver::DaySolver;
|
||||||
use crate::util::read_file;
|
use crate::util::read_file;
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ mod day4;
|
|||||||
mod day5;
|
mod day5;
|
||||||
mod day6;
|
mod day6;
|
||||||
mod day7;
|
mod day7;
|
||||||
|
mod day8;
|
||||||
|
|
||||||
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
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))),
|
5 => Some(Box::new(Day5::create(input))),
|
||||||
6 => Some(Box::new(Day6::create(input))),
|
6 => Some(Box::new(Day6::create(input))),
|
||||||
7 => Some(Box::new(Day7::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))),
|
// 9 => Some(Box::new(Day9::create(input))),
|
||||||
// 10 => Some(Box::new(Day10::create(input))),
|
// 10 => Some(Box::new(Day10::create(input))),
|
||||||
// 11 => Some(Box::new(Day11::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 std::fs;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use num::Integer;
|
use num::{CheckedSub, Integer};
|
||||||
|
|
||||||
pub fn read_file(filename: &str) -> String {
|
pub fn read_file(filename: &str) -> String {
|
||||||
fs::read_to_string(filename)
|
fs::read_to_string(filename)
|
||||||
@@ -148,10 +148,32 @@ impl<T> Coord<T> where T: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[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 {
|
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))
|
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)]
|
#[allow(dead_code)]
|
||||||
@@ -196,4 +218,21 @@ impl Coord<usize> {
|
|||||||
pub fn add_signed(&self, rhs: Coord<isize>) -> 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))
|
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