2023/src/day10.rs

342 lines
10 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!("Day10 - Task02 - Duration: {duration:?} - Caged Tiles: {}", 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[0].1);
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_network.contains(&(y as i32, x as i32)) {
if pipe == &Pipe::Horizontal {
return
}
match pipe {
Pipe::Vertical => is_in_pipe = !is_in_pipe,
Pipe::L => {
last_change = pipe.clone();
is_in_pipe = !is_in_pipe
},
Pipe::F => {
last_change = pipe.clone();
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 {
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);
}