mirror of
https://github.com/anthonyoteri/advent-of-code-2023.git
synced 2026-06-05 17:46:54 -04:00
+209
-5
@@ -1,18 +1,222 @@
|
||||
use crate::error::AocError;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
|
||||
struct Point {
|
||||
row: i32,
|
||||
col: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
struct Pipe {
|
||||
input: Point,
|
||||
output: Point,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
enum Tile {
|
||||
Vertical(Pipe),
|
||||
Horizontal(Pipe),
|
||||
NorthEast(Pipe),
|
||||
NorthWest(Pipe),
|
||||
SouthWest(Pipe),
|
||||
SouthEast(Pipe),
|
||||
Ground,
|
||||
Start,
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> BTreeMap<Point, Tile> {
|
||||
let grid = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.flat_map(|(row, line)| {
|
||||
line.chars().enumerate().map(move |(col, c)| {
|
||||
let pos = Point {
|
||||
row: row as i32,
|
||||
col: col as i32,
|
||||
};
|
||||
|
||||
let tile = match c {
|
||||
'|' => Tile::Vertical(Pipe {
|
||||
input: Point {
|
||||
row: pos.row - 1,
|
||||
col: pos.col,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row + 1,
|
||||
col: pos.col,
|
||||
},
|
||||
}),
|
||||
'-' => Tile::Horizontal(Pipe {
|
||||
input: Point {
|
||||
row: pos.row,
|
||||
col: pos.col - 1,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row,
|
||||
col: pos.col + 1,
|
||||
},
|
||||
}),
|
||||
'L' => Tile::NorthEast(Pipe {
|
||||
input: Point {
|
||||
row: pos.row - 1,
|
||||
col: pos.col,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row,
|
||||
col: pos.col + 1,
|
||||
},
|
||||
}),
|
||||
'J' => Tile::NorthWest(Pipe {
|
||||
input: Point {
|
||||
row: pos.row - 1,
|
||||
col: pos.col,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row,
|
||||
col: pos.col - 1,
|
||||
},
|
||||
}),
|
||||
'7' => Tile::SouthWest(Pipe {
|
||||
input: Point {
|
||||
row: pos.row + 1,
|
||||
col: pos.col,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row,
|
||||
col: pos.col - 1,
|
||||
},
|
||||
}),
|
||||
'F' => Tile::SouthEast(Pipe {
|
||||
input: Point {
|
||||
row: pos.row + 1,
|
||||
col: pos.col,
|
||||
},
|
||||
output: Point {
|
||||
row: pos.row,
|
||||
col: pos.col + 1,
|
||||
},
|
||||
}),
|
||||
'.' => Tile::Ground,
|
||||
'S' => Tile::Start,
|
||||
_ => panic!("Unknown tile: {}", c),
|
||||
};
|
||||
|
||||
(pos, tile)
|
||||
})
|
||||
})
|
||||
.collect::<BTreeMap<Point, Tile>>();
|
||||
|
||||
grid
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn process(input: &str) -> miette::Result<u64, AocError> {
|
||||
Ok(0)
|
||||
let grid = parse(input);
|
||||
|
||||
let mut main_loop = BTreeMap::default();
|
||||
|
||||
let start: &Point = grid
|
||||
.iter()
|
||||
.find(|(_, tile)| **tile == Tile::Start)
|
||||
.map(|(pos, _)| pos)
|
||||
.unwrap();
|
||||
|
||||
let start_connects: Vec<&Point> = grid
|
||||
.iter()
|
||||
.filter(|(_, tile)| match tile {
|
||||
Tile::Vertical(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
Tile::Horizontal(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
Tile::NorthEast(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
Tile::NorthWest(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
Tile::SouthWest(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
Tile::SouthEast(pipe) => pipe.input == *start || pipe.output == *start,
|
||||
_ => false,
|
||||
})
|
||||
.map(|(pos, _)| pos)
|
||||
.collect();
|
||||
|
||||
let mut current = *start_connects.first().unwrap();
|
||||
let mut prev = start;
|
||||
while current != start {
|
||||
let tile = grid.get(current).unwrap();
|
||||
match tile {
|
||||
Tile::Vertical(p)
|
||||
| Tile::Horizontal(p)
|
||||
| Tile::NorthEast(p)
|
||||
| Tile::NorthWest(p)
|
||||
| Tile::SouthEast(p)
|
||||
| Tile::SouthWest(p) => {
|
||||
if p.input == *prev {
|
||||
prev = current;
|
||||
current = &p.output;
|
||||
main_loop.insert(current, tile);
|
||||
main_loop.insert(prev, tile);
|
||||
} else {
|
||||
prev = current;
|
||||
current = &p.input;
|
||||
main_loop.insert(current, tile);
|
||||
main_loop.insert(prev, tile);
|
||||
}
|
||||
}
|
||||
_ => panic!("Unknown tile: {:?}", tile),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(grid
|
||||
.iter()
|
||||
.filter(|(pos, _)| !main_loop.contains_key(pos))
|
||||
.filter_map(|(pos, _)| {
|
||||
let tiles_in_row = main_loop.keys().filter(|p| p.row == pos.row);
|
||||
let count_west = tiles_in_row
|
||||
.clone()
|
||||
.filter(|t| {
|
||||
matches!(
|
||||
main_loop.get(*t),
|
||||
Some(Tile::Vertical(_))
|
||||
| Some(Tile::Start)
|
||||
| Some(Tile::SouthEast(_))
|
||||
| Some(Tile::SouthWest(_))
|
||||
) && t.col < pos.col
|
||||
})
|
||||
.count();
|
||||
let count_east = tiles_in_row
|
||||
.clone()
|
||||
.filter(|t| {
|
||||
matches!(
|
||||
main_loop.get(*t),
|
||||
Some(Tile::Vertical(_))
|
||||
| Some(Tile::Start)
|
||||
| Some(Tile::SouthEast(_))
|
||||
| Some(Tile::SouthWest(_))
|
||||
) && t.col > pos.col
|
||||
})
|
||||
.count();
|
||||
|
||||
if count_west % 2 != 0 && (count_east % 2 != 0 || count_east != 0) {
|
||||
Some(1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.count() as u64)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rstest::rstest;
|
||||
|
||||
#[test_log::test]
|
||||
fn test_process() -> miette::Result<()> {
|
||||
let input = include_str!("../test-input.txt");
|
||||
assert_eq!(0, process(input)?);
|
||||
#[test_log::test(rstest)]
|
||||
#[case("test-input3.txt", 4)]
|
||||
#[case("test-input4.txt", 8)]
|
||||
#[case("test-input5.txt", 10)]
|
||||
fn test_process(#[case] filename: &str, #[case] expected: usize) -> miette::Result<()> {
|
||||
let input =
|
||||
String::from_utf8_lossy(&std::fs::read(std::path::Path::new(filename)).unwrap())
|
||||
.parse::<String>()
|
||||
.unwrap();
|
||||
assert_eq!(expected, process(&input)? as usize);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
...........
|
||||
.S-------7.
|
||||
.|F-----7|.
|
||||
.||.....||.
|
||||
.||.....||.
|
||||
.|L-7.F-J|.
|
||||
.|..|.|..|.
|
||||
.L--J.L--J.
|
||||
...........
|
||||
@@ -0,0 +1,10 @@
|
||||
.F----7F7F7F7F-7....
|
||||
.|F--7||||||||FJ....
|
||||
.||.FJ||||||||L7....
|
||||
FJL7L7LJLJ||LJ.L-7..
|
||||
L--J.L7...LJS7F-7L7.
|
||||
....F-J..F7FJ|L7L7L7
|
||||
....L7.F7||L7|.L7L7|
|
||||
.....|FJLJ|FJ|F7|.LJ
|
||||
....FJL-7.||.||||...
|
||||
....L---J.LJ.LJLJ...
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user