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