[TASK] Day 3
This commit is contained in:
139
src/day3.rs
Normal file
139
src/day3.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::day_solver::DaySolver;
|
||||
use crate::util::Coord;
|
||||
|
||||
use super::util;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Day3 {
|
||||
numbers: Vec<(Coord<usize>, u32)>,
|
||||
symbols: HashSet<Coord<usize>>,
|
||||
gears: Vec<Coord<usize>>
|
||||
}
|
||||
|
||||
impl Day3 {
|
||||
|
||||
pub fn create(input_filename: String) -> Self {
|
||||
let lines = util::read_file(&input_filename);
|
||||
// let lines = util::read_file("input/dayX.txt");
|
||||
|
||||
let mut numbers = Vec::new();
|
||||
let mut symbols = HashSet::new();
|
||||
let mut gears = Vec::new();
|
||||
|
||||
for (y, line) in lines.iter().enumerate() {
|
||||
let mut cur_num= Vec::new();
|
||||
for (x, c) in line.char_indices() {
|
||||
if c.is_numeric() {
|
||||
cur_num.push(c)
|
||||
} else {
|
||||
if !cur_num.is_empty() {
|
||||
numbers.push((
|
||||
Coord::new(x - cur_num.len(), y),
|
||||
cur_num.to_owned().into_iter().collect::<String>().parse::<u32>().unwrap()
|
||||
));
|
||||
cur_num.clear();
|
||||
}
|
||||
|
||||
if c != '.' {
|
||||
// A symbol!
|
||||
symbols.insert(Coord::new(x, y));
|
||||
}
|
||||
|
||||
if c == '*' {
|
||||
gears.push(Coord::new(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the line ends with a number, we still need to process it...
|
||||
if !cur_num.is_empty() {
|
||||
numbers.push((
|
||||
Coord::new(line.len() - cur_num.len(), y),
|
||||
cur_num.to_owned().into_iter().collect::<String>().parse::<u32>().unwrap()
|
||||
));
|
||||
cur_num.clear();
|
||||
}
|
||||
|
||||
}
|
||||
// Put the input into the day struct
|
||||
return Day3 {
|
||||
numbers,
|
||||
symbols,
|
||||
gears
|
||||
}
|
||||
}
|
||||
|
||||
fn has_adjacent_symbol(&self, pos: &Coord<usize>, n: &u32) -> bool {
|
||||
let n_len = Self::number_length(n);
|
||||
for y in pos.y.checked_sub(1).unwrap_or(0)..pos.y + 2 {
|
||||
for x in pos.x.checked_sub(1).unwrap_or(0)..pos.x + n_len + 1 {
|
||||
if self.symbols.contains(&Coord::new(x, y)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fn get_adjacent_numbers(&self, pos: &Coord<usize>) -> Vec<u32> {
|
||||
|
||||
return self.numbers.iter()
|
||||
.filter(|cn| self.is_adjacent(&pos, cn))
|
||||
.map(|(_, n)| n.to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_adjacent(&self, pos: &Coord<usize>, number: &(Coord<usize>, u32)) -> bool {
|
||||
|
||||
return pos.x >= number.0.x.checked_sub(1).unwrap_or(0) && pos.x <= number.0.x + Self::number_length(&number.1) &&
|
||||
pos.y >= number.0.y.checked_sub(1).unwrap_or(0) && pos.y <= number.0.y + 1
|
||||
}
|
||||
|
||||
fn number_length(n: &u32) -> usize {
|
||||
n.to_string().len()
|
||||
}
|
||||
}
|
||||
|
||||
impl DaySolver for Day3 {
|
||||
|
||||
|
||||
fn solve_part1(&mut self) -> String {
|
||||
// println!("{:?}", self);
|
||||
let mut sum = 0u32;
|
||||
for (pos, n) in &self.numbers {
|
||||
if self.has_adjacent_symbol(&pos, n) {
|
||||
sum += n;
|
||||
// } else {
|
||||
// println!("No adjacent symbol for {}", n);
|
||||
}
|
||||
}
|
||||
sum.to_string()
|
||||
}
|
||||
|
||||
fn solve_part2(&mut self) -> String {
|
||||
|
||||
let mut sum = 0;
|
||||
|
||||
for gear in &self.gears {
|
||||
let adjacent = self.get_adjacent_numbers(gear);
|
||||
if adjacent.len() > 1 {
|
||||
sum += adjacent.iter().product::<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
sum.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
let mut day3 = Day3::create("input/day03_example.txt".to_string());
|
||||
assert_eq!("4361", day3.solve_part1());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
let mut day3 = Day3::create("input/day03_example.txt".to_string());
|
||||
assert_eq!("467835", day3.solve_part2());
|
||||
}
|
||||
@@ -3,14 +3,16 @@ extern crate core;
|
||||
use std::time::Instant;
|
||||
use crate::day1::Day1;
|
||||
use crate::day2::Day2;
|
||||
use crate::day3::Day3;
|
||||
use crate::day_solver::DaySolver;
|
||||
|
||||
mod util;
|
||||
mod day1;
|
||||
mod day2;
|
||||
mod day3;
|
||||
mod day_solver;
|
||||
|
||||
const MAX_DAY: u8 = 2;
|
||||
const MAX_DAY: u8 = 3;
|
||||
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
||||
|
||||
fn main() {
|
||||
@@ -73,9 +75,12 @@ struct AocBenchResult {
|
||||
}
|
||||
|
||||
fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
|
||||
|
||||
let input_filename = format!("input/day{:02}.txt",day);
|
||||
match day {
|
||||
1 => Some(Box::new(Day1::create())),
|
||||
2 => Some(Box::new(Day2::create())),
|
||||
3 => Some(Box::new(Day3::create(input_filename))),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ impl <T: Display + Clone + Sized> Grid<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Coord<T> where T: Sized {
|
||||
pub x: T,
|
||||
pub y: T
|
||||
|
||||
Reference in New Issue
Block a user