1
0
Fork 0

day(10): add solution

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2023-12-10 17:15:03 +01:00
parent 4a2e0fef55
commit f2829381c8
Signed by: mfocko
GPG key ID: 7C47D46246790496
3 changed files with 241 additions and 0 deletions

5
samples/day10_1.txt Normal file
View file

@ -0,0 +1,5 @@
7-F7-
.FJ|7
SJLL7
|F--J
LJ.LJ

10
samples/day10_2.txt Normal file
View file

@ -0,0 +1,10 @@
FF7FSF7F7F7F7F7F---7
L|LJ||||||||||||F--J
FL-7LJLJ||||||LJL-77
F--JF--7||LJLJ7F7FJ-
L---JF-JLJ.||-FJLJJ7
|F|F-JF---7F7-L7L|7|
|FFJF7L7F-JF7|JL---7
7-L-JL7||F7|L7F-7F7|
L.L7LFJ|||||FJL7||LJ
L7JLJL-JLJLJL--JLJ.L

226
src/bin/day10.rs Normal file
View file

@ -0,0 +1,226 @@
use std::{collections::VecDeque, fmt::Display, fmt::Write};
use aoc_2023::*;
type Output1 = i32;
type Output2 = Output1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Tile {
Vertical,
Horizontal,
NorthEast,
NorthWest,
SouthWest,
SouthEast,
Ground,
Start,
}
impl Tile {
fn connections(&self) -> Vec<Vector2D<isize>> {
match self {
Tile::Vertical => vec![Vector2D::new(0, -1), Vector2D::new(0, 1)],
Tile::Horizontal => vec![Vector2D::new(-1, 0), Vector2D::new(1, 0)],
Tile::NorthEast => vec![Vector2D::new(0, -1), Vector2D::new(1, 0)],
Tile::NorthWest => vec![Vector2D::new(0, -1), Vector2D::new(-1, 0)],
Tile::SouthWest => vec![Vector2D::new(-1, 0), Vector2D::new(0, 1)],
Tile::SouthEast => vec![Vector2D::new(0, 1), Vector2D::new(1, 0)],
Tile::Ground => vec![],
Tile::Start => vec![
Vector2D::new(0, -1),
Vector2D::new(0, 1),
Vector2D::new(-1, 0),
Vector2D::new(1, 0),
],
}
}
fn next(&self, position: Vector2D<isize>) -> Vec<Vector2D<isize>> {
self.connections()
.iter()
.map(|dv| *dv + position)
.collect_vec()
}
}
impl From<char> for Tile {
fn from(value: char) -> Self {
match value {
'|' => Self::Vertical,
'-' => Self::Horizontal,
'L' => Self::NorthEast,
'J' => Self::NorthWest,
'7' => Self::SouthWest,
'F' => Self::SouthEast,
'.' => Self::Ground,
'S' => Self::Start,
_ => unreachable!("{} is an invalid tile", value),
}
}
}
impl Display for Tile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_char(match self {
Tile::Vertical => '║',
Tile::Horizontal => '═',
Tile::NorthEast => '╚',
Tile::NorthWest => '╝',
Tile::SouthWest => '╗',
Tile::SouthEast => '╔',
Tile::Ground => ' ',
Tile::Start => 'S',
})
}
}
impl From<Tile> for char {
fn from(value: Tile) -> Self {
match value {
Tile::Vertical => '|',
Tile::Horizontal => '-',
Tile::NorthEast => 'L',
Tile::NorthWest => 'J',
Tile::SouthWest => '7',
Tile::SouthEast => 'F',
Tile::Ground => '.',
Tile::Start => 'S',
}
}
}
struct TileMap<'a>(&'a [Vec<Tile>]);
impl Display for TileMap<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for row in self.0 {
for tile in row {
f.write_fmt(format_args!("{}", tile))?;
}
f.write_char('\n')?;
}
Ok(())
}
}
struct Day10 {
pipes: Vec<Vec<Tile>>,
distances: Vec<Vec<i32>>,
}
impl Day10 {
fn find_start(&self) -> Vector2D<isize> {
for y in 0..self.pipes.len() {
for x in 0..self.pipes[y].len() {
if self.pipes[y][x] == Tile::Start {
return Vector2D::new(x.try_into().unwrap(), y.try_into().unwrap());
}
}
}
unreachable!("there's always start")
}
fn bfs(&mut self) {
let mut distances = vec![vec![-1; self.pipes[0].len()]; self.pipes.len()];
// find the start and set the initial distance to zero
let start = self.find_start();
distances[start] = 0;
let mut q = VecDeque::from([start]);
while let Some(p) = q.pop_front() {
for neighbour in self.pipes[p].next(p) {
if in_range(&distances, &neighbour)
&& distances[neighbour] == -1
&& self.pipes[neighbour].next(neighbour).contains(&p)
{
distances[neighbour] = distances[p] + 1;
q.push_back(neighbour);
}
}
}
self.distances = distances;
// debug!("{:?}", distances);
}
}
impl Solution<Output1, Output2> for Day10 {
fn new<P: AsRef<Path>>(pathname: P) -> Self {
Self {
pipes: file_to_string(pathname)
.lines()
.map(|s| s.chars().map(|c| c.into()).collect_vec())
.collect_vec(),
distances: vec![vec![]],
}
}
fn part_1(&mut self) -> Output1 {
self.bfs();
self.distances
.iter()
.map(|row| *row.iter().max().unwrap())
.max()
.unwrap()
}
fn part_2(&mut self) -> Output2 {
self.bfs();
let mut counter = 0;
let mut horizontally_enclosed_west = vec![false; self.pipes[0].len()];
let mut horizontally_enclosed_east = vec![false; self.pipes[0].len()];
for (y, row) in self.pipes.iter().enumerate() {
let mut vertically_enclosed_north = false;
let mut vertically_enclosed_south = false;
for (x, &t) in row.iter().enumerate() {
if self.distances[y][x] != -1 {
if matches!(
t,
Tile::Vertical | Tile::NorthEast | Tile::NorthWest | Tile::Start
) {
vertically_enclosed_north = !vertically_enclosed_north;
}
if matches!(
t,
Tile::Vertical | Tile::SouthEast | Tile::SouthWest | Tile::Start
) {
vertically_enclosed_south = !vertically_enclosed_south;
}
if matches!(
t,
Tile::Horizontal | Tile::NorthWest | Tile::SouthWest | Tile::Start
) {
horizontally_enclosed_west[x] = !horizontally_enclosed_west[x];
}
if matches!(
t,
Tile::Horizontal | Tile::NorthEast | Tile::SouthEast | Tile::Start
) {
horizontally_enclosed_east[x] = !horizontally_enclosed_east[x];
}
} else if (vertically_enclosed_north || vertically_enclosed_south)
&& (horizontally_enclosed_east[x] || horizontally_enclosed_west[x])
{
counter += 1;
}
}
}
counter
}
}
fn main() -> Result<()> {
Day10::main()
}
test_sample!(day_10, Day10, 8, 10);