1
Fork 0
advent-of-code/source/day_05/mod.rs

164 lines
3.7 KiB
Rust

use std::{collections::HashMap, str::FromStr};
use color_eyre::{
eyre::{eyre, Error},
Result,
};
pub fn solve() -> Result<()> {
let input_data = include_str!("../../data/day_05.txt").trim();
println!("Day 05 Part 1: {}", part_1(input_data)?);
println!("Day 05 Part 2: {}", part_2(input_data)?);
Ok(())
}
#[derive(Debug)]
struct Vector {
a: (isize, isize),
b: (isize, isize),
}
impl Vector {
fn diagonal_coordinates(&self) -> Vec<(isize, isize)> {
let x_coordinates = {
let x_amount = (self.a.0 - self.b.0).abs();
if self.a.0 < self.b.0 {
(0..=x_amount)
.into_iter()
.map(|x| self.a.0 + x)
.collect::<Vec<_>>()
} else {
(0..=x_amount)
.into_iter()
.map(|x| self.a.0 - x)
.collect::<Vec<_>>()
}
};
let y_coordinates = {
let y_amount = (self.a.1 - self.b.1).abs();
if self.a.1 < self.b.1 {
(0..=y_amount)
.into_iter()
.map(|x| self.a.1 + x)
.collect::<Vec<_>>()
} else {
(0..=y_amount)
.into_iter()
.map(|x| self.a.1 - x)
.collect::<Vec<_>>()
}
};
x_coordinates.into_iter().zip(y_coordinates).collect()
}
fn horizontal_coordinates(&self) -> Vec<(isize, isize)> {
let y = self.a.1;
let (x1, x2) = if self.a.0 < self.b.0 {
(self.a.0, self.b.0)
} else {
(self.b.0, self.a.0)
};
(x1..=x2).into_iter().map(|x| (x, y)).collect()
}
fn vertical_coordinates(&self) -> Vec<(isize, isize)> {
let x = self.a.0;
let (y1, y2) = if self.a.1 < self.b.1 {
(self.a.1, self.b.1)
} else {
(self.b.1, self.a.1)
};
(y1..=y2).into_iter().map(|y| (x, y)).collect()
}
}
impl FromStr for Vector {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let numbers = s
.replace(" -> ", ",")
.split(",")
.map(str::parse)
.collect::<Result<Vec<_>, _>>()?;
if numbers.len() == 4 {
Ok(Self {
a: (numbers[0], numbers[1]),
b: (numbers[2], numbers[3]),
})
} else {
Err(eyre!("Invalid input: {}", s))
}
}
}
fn part_1(input: &str) -> Result<usize> {
let vectors = input
.lines()
.filter_map(|line| {
if let Ok(vector) = Vector::from_str(line) {
if vector.a.0 == vector.b.0 || vector.a.1 == vector.b.1 {
return Some(vector);
}
}
None
})
.collect::<Vec<_>>();
let mut travelled_coordinates = HashMap::<(isize, isize), isize>::new();
for vector in vectors {
let coordinates = if vector.a.0 == vector.b.0 {
vector.vertical_coordinates()
} else {
vector.horizontal_coordinates()
};
for coordinate in coordinates {
let amount = travelled_coordinates.entry(coordinate).or_default();
*amount += 1;
}
}
Ok(count_result(travelled_coordinates))
}
fn part_2(input: &str) -> Result<usize> {
let vectors = input
.lines()
.map(str::parse)
.collect::<Result<Vec<Vector>>>()?;
let mut travelled_coordinates = HashMap::<(isize, isize), isize>::new();
for vector in vectors {
let coordinates = if vector.a.0 == vector.b.0 {
vector.vertical_coordinates()
} else if vector.a.1 == vector.b.1 {
vector.horizontal_coordinates()
} else {
vector.diagonal_coordinates()
};
for coordinate in coordinates {
let amount = travelled_coordinates.entry(coordinate).or_default();
*amount += 1;
}
}
Ok(count_result(travelled_coordinates))
}
fn count_result(coordinates: HashMap<(isize, isize), isize>) -> usize {
coordinates
.into_iter()
.filter(|(_, amount)| amount >= &2)
.count()
}