day(10): add solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
4a2e0fef55
commit
f2829381c8
3 changed files with 241 additions and 0 deletions
5
samples/day10_1.txt
Normal file
5
samples/day10_1.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
7-F7-
|
||||||
|
.FJ|7
|
||||||
|
SJLL7
|
||||||
|
|F--J
|
||||||
|
LJ.LJ
|
10
samples/day10_2.txt
Normal file
10
samples/day10_2.txt
Normal 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
226
src/bin/day10.rs
Normal 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);
|
Loading…
Reference in a new issue