335 lines
9.9 KiB
Rust
335 lines
9.9 KiB
Rust
|
use std::time::Instant;
|
||
|
|
||
|
#[derive(PartialEq, Clone)]
|
||
|
enum Pipe {
|
||
|
Vertical, // |
|
||
|
Horizontal, // -
|
||
|
L, // North with East
|
||
|
J, // North with West
|
||
|
Pipe7, // South with West
|
||
|
F, // South with East
|
||
|
Dot, // Nothing
|
||
|
S, // Start Point
|
||
|
}
|
||
|
|
||
|
impl From<char> for Pipe {
|
||
|
fn from(value: char) -> Self {
|
||
|
match value {
|
||
|
'|' => Pipe::Vertical,
|
||
|
'-' => Pipe::Horizontal,
|
||
|
'L' => Pipe::L,
|
||
|
'J' => Pipe::J,
|
||
|
'7' => Pipe::Pipe7,
|
||
|
'F' => Pipe::F,
|
||
|
'.' => Pipe::Dot,
|
||
|
'S' => Pipe::S,
|
||
|
_ => Pipe::Dot
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Pipe {
|
||
|
fn next(&self, from: (i32, i32), current: (i32, i32)) -> (i32, i32) {
|
||
|
let diff_y = current.0 - from.0;
|
||
|
let diff_x = current.1 - from.1;
|
||
|
if diff_y == 0 {
|
||
|
// From East or West
|
||
|
if diff_x > 0 {
|
||
|
// From West
|
||
|
match self {
|
||
|
Pipe::Horizontal => (current.0, current.1 + 1), // To East
|
||
|
Pipe::J => (current.0 - 1, current.1), // To North
|
||
|
Pipe::Pipe7 => (current.0 + 1, current.1), // To South
|
||
|
_ => (0,0)
|
||
|
}
|
||
|
} else {
|
||
|
// From East
|
||
|
match self {
|
||
|
Pipe::Horizontal => (current.0, current.1 - 1), // To West
|
||
|
Pipe::L => (current.0 - 1, current.1), // To North
|
||
|
Pipe::F => (current.0 + 1, current.1 ), // To South
|
||
|
_ => (0,0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else if diff_y > 0{
|
||
|
// From North
|
||
|
match self {
|
||
|
Pipe::Vertical => (current.0 + 1, current.1), // To South
|
||
|
Pipe::J => (current.0, current.1 - 1), // To West
|
||
|
Pipe::L => (current.0, current.1 + 1), // To East
|
||
|
_ => (0,0)
|
||
|
}
|
||
|
} else {
|
||
|
// From South
|
||
|
match self {
|
||
|
Pipe::Vertical => (current.0 - 1, current.1), // To North
|
||
|
Pipe::Pipe7 => (current.0, current.1 - 1), // To West
|
||
|
Pipe::F => (current.0, current.1 + 1), // To East
|
||
|
_ => (0,0)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn execute_task01(content: &str) {
|
||
|
let start = Instant::now();
|
||
|
let sum_of_b = solve_01(content).unwrap();
|
||
|
let duration = start.elapsed();
|
||
|
|
||
|
//assert_eq!(1953784198, sum_of_b);
|
||
|
println!("Day10 - Task01 - Duration: {duration:?} - Farthest Point: {}", sum_of_b)
|
||
|
}
|
||
|
|
||
|
pub fn execute_task02(content: &str) {
|
||
|
let start = Instant::now();
|
||
|
let command_steps = solve_02(content).unwrap();
|
||
|
let duration = start.elapsed();
|
||
|
|
||
|
//assert_eq!(957, command_steps);
|
||
|
println!("Day09 - Task02 - Duration: {duration:?} - Sum of B: {}", command_steps)
|
||
|
}
|
||
|
|
||
|
|
||
|
fn solve_01(content: &str) -> anyhow::Result<usize> {
|
||
|
let mut map = build_map(content);
|
||
|
let (starting, directions) = find_start(&map);
|
||
|
|
||
|
map[starting.1.0 as usize][starting.1.1 as usize] = starting.0;
|
||
|
|
||
|
let from = (starting.1.0 + directions[0].0, starting.1.1 + directions[1].0);
|
||
|
let mut pipe_network = vec![from ,starting.1];
|
||
|
|
||
|
solve_pipeline(&map, &mut pipe_network);
|
||
|
|
||
|
Ok(pipe_network.len()/2)
|
||
|
}
|
||
|
|
||
|
fn solve_02(content: &str) -> anyhow::Result<i32> {
|
||
|
let mut map = build_map(content);
|
||
|
let (starting, directions) = find_start(&map);
|
||
|
|
||
|
map[starting.1.0 as usize][starting.1.1 as usize] = starting.0;
|
||
|
|
||
|
let from = (starting.1.0 + directions[0].0, starting.1.1 + directions[1].0);
|
||
|
let mut pipe_network = vec![from ,starting.1];
|
||
|
|
||
|
solve_pipeline(&map, &mut pipe_network);
|
||
|
|
||
|
let mut is_in_pipe = false;
|
||
|
let mut last_change = Pipe::Dot;
|
||
|
let mut size_of_caged_tiles = 0;
|
||
|
|
||
|
map.iter()
|
||
|
.enumerate()
|
||
|
.for_each(|(y, column)| column.iter()
|
||
|
.enumerate()
|
||
|
.for_each(|(x, pipe)| {
|
||
|
if pipe == &Pipe::Horizontal {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if pipe_network.contains(&(y as i32, x as i32)) {
|
||
|
match pipe {
|
||
|
Pipe::Vertical => is_in_pipe = !is_in_pipe,
|
||
|
Pipe::L => is_in_pipe = !is_in_pipe,
|
||
|
Pipe::F => is_in_pipe = !is_in_pipe,
|
||
|
Pipe::Pipe7 => {
|
||
|
if last_change != Pipe::F {
|
||
|
is_in_pipe = !is_in_pipe
|
||
|
}
|
||
|
},
|
||
|
Pipe::J => {
|
||
|
if last_change != Pipe::L {
|
||
|
is_in_pipe = !is_in_pipe
|
||
|
}
|
||
|
},
|
||
|
_ => panic!("HELP")
|
||
|
};
|
||
|
} else {
|
||
|
if is_in_pipe {
|
||
|
println!("Find Tile: ({y},{x})");
|
||
|
size_of_caged_tiles += 1;
|
||
|
}
|
||
|
}
|
||
|
}));
|
||
|
|
||
|
Ok(size_of_caged_tiles)
|
||
|
}
|
||
|
|
||
|
|
||
|
fn build_map(content: &str) -> Vec<Vec<Pipe>> {
|
||
|
content
|
||
|
.lines()
|
||
|
.map(|line| line.chars().map(|c| Pipe::from(c)).collect::<Vec<Pipe>>())
|
||
|
.collect::<Vec<Vec<Pipe>>>()
|
||
|
}
|
||
|
|
||
|
fn find_start(map: &Vec<Vec<Pipe>>) -> ((Pipe, (i32, i32)), Vec<(i32, i32)>) {
|
||
|
|
||
|
let mut starting: (Pipe, (i32, i32)) = (Pipe::Dot, (0, 0));
|
||
|
let mut directions: Vec<(i32, i32)> = vec![];
|
||
|
|
||
|
'outer: for (y, line) in map.iter().enumerate() {
|
||
|
for (x, c) in line.iter().enumerate() {
|
||
|
if c == &Pipe::S {
|
||
|
// Find starting, now replace with correct Pipe
|
||
|
|
||
|
// North exists
|
||
|
if y > 0 {
|
||
|
let north_pipe = &map[y - 1][x];
|
||
|
if north_pipe == &Pipe::Pipe7 || north_pipe == &Pipe::F || north_pipe == &Pipe::Vertical {
|
||
|
directions.push((-1, 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// South exists
|
||
|
if map.len() > (y + 1) {
|
||
|
let south_pipe = &map[y + 1][x];
|
||
|
if south_pipe == &Pipe::L || south_pipe == &Pipe::J || south_pipe == &Pipe::Vertical {
|
||
|
directions.push((1, 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// West exists
|
||
|
if x > 0 {
|
||
|
let west_pipe = &map[y][x - 1];
|
||
|
if west_pipe == &Pipe::L || west_pipe == &Pipe::F || west_pipe == &Pipe::Horizontal {
|
||
|
directions.push((0, -1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// East exists
|
||
|
if map[y].len() > (x + 1) {
|
||
|
let east_pipe = &map[y][x + 1];
|
||
|
if east_pipe == &Pipe::J || east_pipe == &Pipe::Pipe7 || east_pipe == &Pipe::Horizontal {
|
||
|
directions.push((0, 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// North (-1, 0) with South (1, 0) => (0,0) Vertical
|
||
|
// North (-1, 0) with East (0, 1) => (0,0)
|
||
|
// North (-1, 0) with West (0, -1) => (0,0)
|
||
|
// North (-1, 0) with South (1, 0) => (0,0)
|
||
|
// North (-1, 0) with South (1, 0) => (0,0)
|
||
|
// North (-1, 0) with South (1, 0) => (0,0)
|
||
|
// North (-1, 0) with South (1, 0) => (0,0)
|
||
|
let pipe = match (directions[0], directions[1]) {
|
||
|
((-1, 0), (1, 0)) => Pipe::Vertical, // North to South
|
||
|
((-1, 0), (0, 1)) => Pipe::L, // North to East
|
||
|
((-1, 0), (0, -1)) => Pipe::J, // North to West
|
||
|
((1, 0), (-1, 0)) => Pipe::Vertical, // South to North
|
||
|
((1, 0), (0, 1)) => Pipe::F, // South to East
|
||
|
((1, 0), (0, -1)) => Pipe::Pipe7,// South to West
|
||
|
((0, -1), (1, 0)) => Pipe::Pipe7, // West to South
|
||
|
((0, -1), (0, 1)) => Pipe::Horizontal, // West to East
|
||
|
((0, -1), (-1, 0)) => Pipe::J, // West to North
|
||
|
((0, 1), (1, 0)) => Pipe::F, // East to South
|
||
|
((0, 1), (-1, 0)) => Pipe::L, // East to North
|
||
|
((0, 1), (0, -1)) => Pipe::Horizontal, // East to West
|
||
|
(_, _) => Pipe::Dot
|
||
|
};
|
||
|
|
||
|
starting = (pipe, (y as i32, x as i32));
|
||
|
break 'outer
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(starting, directions)
|
||
|
}
|
||
|
|
||
|
fn solve_pipeline(map: &Vec<Vec<Pipe>>, pipe_network: &mut Vec<(i32, i32)>) {
|
||
|
|
||
|
loop {
|
||
|
let from = pipe_network[pipe_network.len() -2].clone();
|
||
|
let latest = pipe_network.last().unwrap().clone();
|
||
|
let pipe = &map[latest.0 as usize][latest.1 as usize];
|
||
|
let new = pipe.next(from.clone(), latest.clone());
|
||
|
|
||
|
if pipe_network.contains(&new) {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
pipe_network.push(new);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_solve_01() {
|
||
|
let example = r#".....
|
||
|
.S-7.
|
||
|
.|.|.
|
||
|
.L-J.
|
||
|
....."#;
|
||
|
|
||
|
let result = solve_01(example).unwrap();
|
||
|
|
||
|
assert_eq!(4, result);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_solve_01_2() {
|
||
|
let example = r#"..F7.
|
||
|
.FJ|.
|
||
|
SJ.L7
|
||
|
|F--J
|
||
|
LJ..."#;
|
||
|
|
||
|
let result = solve_01(example).unwrap();
|
||
|
|
||
|
assert_eq!(8, result);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_solve_02() {
|
||
|
let example = r#"...........
|
||
|
.S-------7.
|
||
|
.|F-----7|.
|
||
|
.||.....||.
|
||
|
.||.....||.
|
||
|
.|L-7.F-J|.
|
||
|
.|..|.|..|.
|
||
|
.L--J.L--J.
|
||
|
..........."#;
|
||
|
|
||
|
let result = solve_02(example).unwrap();
|
||
|
|
||
|
assert_eq!(4, result);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_solve_02_2() {
|
||
|
let example = r#".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..."#;
|
||
|
|
||
|
let result = solve_02(example).unwrap();
|
||
|
|
||
|
assert_eq!(8, result);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_solve_02_3() {
|
||
|
let example = r#"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"#;
|
||
|
|
||
|
let result = solve_02(example).unwrap();
|
||
|
|
||
|
assert_eq!(10, result);
|
||
|
}
|