day10: Cleanup
This commit is contained in:
parent
f8e42fd4b9
commit
a59be70c63
439
src/day10/1.rs
439
src/day10/1.rs
|
@ -1,15 +1,95 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
const INPUTS: [&str; 4] = [
|
||||||
|
".....
|
||||||
|
.S-7.
|
||||||
|
.|.|.
|
||||||
|
.L-J.
|
||||||
|
.....",
|
||||||
|
"..F7.
|
||||||
|
.FJ|.
|
||||||
|
SJ.L7
|
||||||
|
|F--J
|
||||||
|
LJ...",
|
||||||
|
include_str!("./sample.txt"),
|
||||||
|
include_str!("./input.txt"),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Direction {
|
||||||
|
Unknown,
|
||||||
|
North,
|
||||||
|
South,
|
||||||
|
East,
|
||||||
|
West,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
|
enum Tile {
|
||||||
|
Vertical = 0x1,
|
||||||
|
Horizontal = 0x2,
|
||||||
|
L = 0x4,
|
||||||
|
J = 0x8,
|
||||||
|
Seven = 0x10,
|
||||||
|
F = 0x20,
|
||||||
|
Ground = 0x40,
|
||||||
|
Start = 0x80,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<char> for Tile {
|
||||||
|
fn from(value: char) -> Self {
|
||||||
|
use Tile::*;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
'|' => Vertical,
|
||||||
|
'-' => Horizontal,
|
||||||
|
'L' => L,
|
||||||
|
'J' => J,
|
||||||
|
'7' => Seven,
|
||||||
|
'F' => F,
|
||||||
|
'.' => Ground,
|
||||||
|
'S' => Start,
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_direction(a: char, dir: &Direction) -> (Direction, u8) {
|
||||||
|
use Direction::*;
|
||||||
|
use Tile::*;
|
||||||
|
match (a, dir) {
|
||||||
|
('|', Unknown | North) => (North, Vertical as u8 | Seven as u8 | F as u8),
|
||||||
|
('|', South) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
|
||||||
|
('-', Unknown | West) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
('-', East) => (East, Horizontal as u8 | J as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('L', Unknown | West) => (North, Vertical as u8 | Seven as u8 | F as u8),
|
||||||
|
('L', South) => (East, Horizontal as u8 | J as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('J', Unknown | South) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
('J', East) => (North, Vertical as u8 | F as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('7', Unknown | East) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
('7', North) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
|
||||||
|
('F', Unknown | North) => (East, Horizontal as u8 | Seven as u8 | J as u8),
|
||||||
|
('F', West) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
|
||||||
|
v => {
|
||||||
|
println!("{:?}", v);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process(data: &str) -> usize {
|
fn process(data: &str) -> usize {
|
||||||
let mut answer = std::usize::MAX;
|
let mut answer = std::usize::MAX;
|
||||||
|
|
||||||
let grid: Vec<Vec<char>> = data
|
let mut grid: Vec<Vec<char>> = data
|
||||||
.lines()
|
.lines()
|
||||||
.filter(|x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.map(|x| x.chars().collect())
|
.map(|x| x.chars().collect())
|
||||||
|
@ -28,336 +108,65 @@ fn process(data: &str) -> usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
'outer: for c in ['-', '|', 'L', 'J', '7', 'F'] {
|
||||||
|
let mut start = true;
|
||||||
|
|
||||||
for mut c in ['F', 'L', '|', '-', 'J', '7'] {
|
|
||||||
let mut sx = s_x;
|
let mut sx = s_x;
|
||||||
let mut sy = s_y;
|
let mut sy = s_y;
|
||||||
let (mut px, mut py) = (s_x, s_y);
|
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
|
grid[sx][sy] = c;
|
||||||
|
|
||||||
while c != 'S' {
|
let mut direction = Direction::Unknown;
|
||||||
println!(
|
|
||||||
"({}, {}) => ({}, {}) c = {} {}",
|
|
||||||
px, py, sx, sy, c, grid[sx][sy]
|
|
||||||
);
|
|
||||||
|
|
||||||
match c {
|
loop {
|
||||||
'|' => {
|
if !start && (sx == s_x && sy == s_y) {
|
||||||
if sx > 0 && !(sx - 1 == px && sy == py) {
|
break;
|
||||||
px = sx;
|
}
|
||||||
py = sy;
|
start = false;
|
||||||
sx = sx - 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1 && !(sx + 1 == px && sy == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx = sx + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'F' => {
|
|
||||||
if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy = sy + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1 && !(sx + 1 == px && px == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx = sx + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'-' => {
|
if length >= answer {
|
||||||
if sy > 0 && !(sx == px && sy - 1 == py) {
|
continue 'outer;
|
||||||
px = sx;
|
}
|
||||||
py = sy;
|
|
||||||
sy = sy - 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy = sy + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'7' => {
|
// what we need to figure out the next step
|
||||||
if sy > 0 && !(sx == px && sy - 1 == py) {
|
// 1. The current character
|
||||||
px = sx;
|
// 2. Direction we are headed in
|
||||||
py = sy;
|
// 3. the potential next character. since it's possible we jump to an un jumpable
|
||||||
sy = sy - 1;
|
// character
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1 && !(sx + 1 == px && sy == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx = sx + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'J' => {
|
let (new_direction, valid_pipes) = next_direction(grid[sx][sy], &direction);
|
||||||
if sy > 0 && !(sx == px && sy - 1 == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy = sy - 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx > 0 && !(sx - 1 == px && sy == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx = sx - 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'L' => {
|
let (x, y) = match new_direction {
|
||||||
if sx > 0 && !(sx - 1 == px && sy == py) {
|
Direction::Unknown => unreachable!(),
|
||||||
px = sx;
|
Direction::North => (-1, 0),
|
||||||
py = sy;
|
Direction::South => (1, 0),
|
||||||
sx = sx - 1;
|
Direction::East => (0, 1),
|
||||||
length += 1;
|
Direction::West => (0, -1),
|
||||||
c = grid[sx][sy];
|
};
|
||||||
} else if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy = sy + 1;
|
|
||||||
length += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'.' => break,
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
let p = sx as i32 + x;
|
||||||
|
let q = sy as i32 + y;
|
||||||
|
if p < 0 || q < 0 || p >= m as i32 || q >= n as i32 {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_pipe = Tile::from(grid[p as usize][q as usize]);
|
||||||
|
if valid_pipes & next_pipe as u8 > 0 {
|
||||||
|
sx = p as usize;
|
||||||
|
sy = q as usize;
|
||||||
|
direction = new_direction;
|
||||||
|
length += 1;
|
||||||
|
} else {
|
||||||
|
continue 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
answer = std::cmp::min(answer, length / 2);
|
answer = std::cmp::min(answer, length / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer;
|
|
||||||
|
|
||||||
// let mut stack = vec![];
|
|
||||||
// // let mut q = VecDeque::new();
|
|
||||||
// stack.push((sx, sy, 'F', sx, sy, 0));
|
|
||||||
// stack.push((sx, sy, 'L', sx, sy, 0));
|
|
||||||
|
|
||||||
let mut min_dist = vec![vec![std::usize::MAX; n]; m];
|
|
||||||
|
|
||||||
// while let Some((sx, sy, c, px, py, distance)) = stack.pop() {
|
|
||||||
// min_dist[sx][sy] = std::cmp::min(min_dist[sx][sy], distance);
|
|
||||||
// match c {
|
|
||||||
// '|' => {
|
|
||||||
// if sx > 0 && !(sx - 1 == px && sy == py) {
|
|
||||||
// let c = grid[sx - 1][sy];
|
|
||||||
// stack.push((sx - 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sx < m - 1 && !(sx + 1 == px && sy == py) {
|
|
||||||
// let c = grid[sx + 1][sy];
|
|
||||||
// stack.push((sx + 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// '-' => {
|
|
||||||
// if sy > 0 && !(sx == px && sy - 1 == py) {
|
|
||||||
// let c = grid[sx][sy - 1];
|
|
||||||
// stack.push((sx, sy - 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
// let c = grid[sx][sy + 1];
|
|
||||||
// stack.push((sx, sy + 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// 'L' => {
|
|
||||||
// if sx > 0 && !(sx - 1 == px && sy == py) {
|
|
||||||
// let c = grid[sx - 1][sy];
|
|
||||||
// stack.push((sx - 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
// let c = grid[sx][sy + 1];
|
|
||||||
// stack.push((sx, sy + 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// 'J' => {
|
|
||||||
// if sy > 0 && !(sx == px && sy - 1 == py) {
|
|
||||||
// let c = grid[sx][sy - 1];
|
|
||||||
// stack.push((sx, sy - 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sx > 0 && !(sx - 1 == px && sy == py) {
|
|
||||||
// let c = grid[sx - 1][sy];
|
|
||||||
// stack.push((sx - 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// '7' => {
|
|
||||||
// if sy > 0 && !(sx == px && sy - 1 == py) {
|
|
||||||
// let c = grid[sx][sy - 1];
|
|
||||||
// stack.push((sx, sy - 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sx < m - 1 && !(sx + 1 == px && sy == py) {
|
|
||||||
// let c = grid[sx + 1][sy];
|
|
||||||
// stack.push((sx + 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// 'F' => {
|
|
||||||
// if sy < n - 1 && !(sx == px && sy + 1 == py) {
|
|
||||||
// let c = grid[sx][sy + 1];
|
|
||||||
// stack.push((sx, sy + 1, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// if sx < m - 1 && !(sx + 1 == px && px == py) {
|
|
||||||
// let c = grid[sx + 1][sy];
|
|
||||||
// stack.push((sx + 1, sy, c, sx, sy, distance + 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// '.' => (),
|
|
||||||
//
|
|
||||||
// 'S' => (),
|
|
||||||
//
|
|
||||||
// v => {
|
|
||||||
// unreachable!()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
println!();
|
|
||||||
|
|
||||||
for line in min_dist {
|
|
||||||
println!("{:?}", line);
|
|
||||||
|
|
||||||
for c in line {
|
|
||||||
if c == std::usize::MAX {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
answer = std::cmp::max(answer, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
|
|
||||||
// for &(sx, sy, c) in [(sx, sy, 'F')].iter() {
|
|
||||||
// let mut visited = vec![vec![false; n]; m];
|
|
||||||
//
|
|
||||||
// // dfs(&grid, &mut visited, &mut path, sx, sy, c, 0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
answer
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dfs(
|
|
||||||
grid: &Vec<Vec<char>>,
|
|
||||||
visited: &mut Vec<Vec<bool>>,
|
|
||||||
path: &mut Vec<char>,
|
|
||||||
sx: usize,
|
|
||||||
sy: usize,
|
|
||||||
c: char,
|
|
||||||
distance: usize,
|
|
||||||
) {
|
|
||||||
if visited[sx][sy] {
|
|
||||||
// return;
|
|
||||||
} else {
|
|
||||||
visited[sx][sy] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if c == 'S' {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
path.push(c);
|
|
||||||
|
|
||||||
println!("({},{}) = {} {}", sx, sy, c, distance);
|
|
||||||
|
|
||||||
let m = grid.len();
|
|
||||||
let n = grid[0].len();
|
|
||||||
|
|
||||||
match c {
|
|
||||||
'|' => {
|
|
||||||
if sx > 0 {
|
|
||||||
let c = grid[sx - 1][sy];
|
|
||||||
dfs(grid, visited, path, sx - 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sx < m - 1 {
|
|
||||||
let c = grid[sx + 1][sy];
|
|
||||||
dfs(grid, visited, path, sx + 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'-' => {
|
|
||||||
if sy > 0 {
|
|
||||||
let c = grid[sx][sy - 1];
|
|
||||||
dfs(grid, visited, path, sx, sy - 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sy < n - 1 {
|
|
||||||
let c = grid[sx][sy + 1];
|
|
||||||
dfs(grid, visited, path, sx, sy + 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'L' => {
|
|
||||||
if sx > 0 {
|
|
||||||
let c = grid[sx - 1][sy];
|
|
||||||
dfs(grid, visited, path, sx - 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sy < n - 1 {
|
|
||||||
let c = grid[sx][sy + 1];
|
|
||||||
dfs(grid, visited, path, sx, sy + 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'J' => {
|
|
||||||
if sy > 0 {
|
|
||||||
let c = grid[sx][sy - 1];
|
|
||||||
dfs(grid, visited, path, sx, sy - 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sx > 0 {
|
|
||||||
let c = grid[sx - 1][sy];
|
|
||||||
dfs(grid, visited, path, sx - 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'7' => {
|
|
||||||
if sy > 0 {
|
|
||||||
let c = grid[sx][sy - 1];
|
|
||||||
dfs(grid, visited, path, sx, sy - 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sx < m - 1 {
|
|
||||||
let c = grid[sx + 1][sy];
|
|
||||||
dfs(grid, visited, path, sx + 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'F' => {
|
|
||||||
if sy < n - 1 {
|
|
||||||
let c = grid[sx][sy + 1];
|
|
||||||
dfs(grid, visited, path, sx, sy + 1, c, distance + 1);
|
|
||||||
}
|
|
||||||
if sx < m - 1 {
|
|
||||||
let c = grid[sx + 1][sy];
|
|
||||||
dfs(grid, visited, path, sx + 1, sy, c, distance + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'.' => (),
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
path.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for input in INPUTS.iter() {
|
for input in INPUTS.iter() {
|
||||||
println!("total = {}", process(input));
|
println!("total = {}", process(input));
|
||||||
|
@ -367,7 +176,7 @@ fn main() {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn part1(b: &mut test::Bencher) {
|
fn part1(b: &mut test::Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let v = process(INPUTS[1]);
|
let v = process(INPUTS[INPUTS.len() - 1]);
|
||||||
test::black_box(v);
|
test::black_box(v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
340
src/day10/2.rs
340
src/day10/2.rs
|
@ -2,7 +2,116 @@
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
const INPUTS: [&str; 5] = [
|
||||||
|
"...........
|
||||||
|
.S-------7.
|
||||||
|
.|F-----7|.
|
||||||
|
.||.....||.
|
||||||
|
.||.....||.
|
||||||
|
.|L-7.F-J|.
|
||||||
|
.|..|.|..|.
|
||||||
|
.L--J.L--J.
|
||||||
|
...........",
|
||||||
|
"..........
|
||||||
|
.S------7.
|
||||||
|
.|F----7|.
|
||||||
|
.||OOOO||.
|
||||||
|
.||OOOO||.
|
||||||
|
.|L-7F-J|.
|
||||||
|
.|II||II|.
|
||||||
|
.L--JL--J.
|
||||||
|
..........",
|
||||||
|
"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",
|
||||||
|
".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...",
|
||||||
|
include_str!("./input.txt"),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Direction {
|
||||||
|
Unknown,
|
||||||
|
North,
|
||||||
|
South,
|
||||||
|
East,
|
||||||
|
West,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
|
enum Tile {
|
||||||
|
Vertical = 0x1,
|
||||||
|
Horizontal = 0x2,
|
||||||
|
L = 0x4,
|
||||||
|
J = 0x8,
|
||||||
|
Seven = 0x10,
|
||||||
|
F = 0x20,
|
||||||
|
Ground = 0x40,
|
||||||
|
Start = 0x80,
|
||||||
|
|
||||||
|
// Reusing a bitmap because these will never be togther in a single map
|
||||||
|
X = 0x1 | 0x2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<char> for Tile {
|
||||||
|
fn from(value: char) -> Self {
|
||||||
|
use Tile::*;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
'|' => Vertical,
|
||||||
|
'-' => Horizontal,
|
||||||
|
'L' => L,
|
||||||
|
'J' => J,
|
||||||
|
'7' => Seven,
|
||||||
|
'F' => F,
|
||||||
|
'.' => Ground,
|
||||||
|
'S' => Start,
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_direction(a: char, dir: &Direction) -> (Direction, u8) {
|
||||||
|
use Direction::*;
|
||||||
|
use Tile::*;
|
||||||
|
match (a, dir) {
|
||||||
|
('|', Unknown | North) => (North, Vertical as u8 | Seven as u8 | F as u8),
|
||||||
|
('|', South) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
|
||||||
|
('-', Unknown | West) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
('-', East) => (East, Horizontal as u8 | J as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('L', Unknown | West) => (North, Vertical as u8 | Seven as u8 | F as u8),
|
||||||
|
('L', South) => (East, Horizontal as u8 | J as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('J', Unknown | South) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
('J', East) => (North, Vertical as u8 | F as u8 | Seven as u8),
|
||||||
|
|
||||||
|
('7', Unknown | East) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
('7', North) => (West, Horizontal as u8 | L as u8 | F as u8),
|
||||||
|
|
||||||
|
('F', Unknown | North) => (East, Horizontal as u8 | Seven as u8 | J as u8),
|
||||||
|
('F', West) => (South, Vertical as u8 | L as u8 | J as u8),
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process(data: &str) -> usize {
|
fn process(data: &str) -> usize {
|
||||||
let mut answer = 0;
|
let mut answer = 0;
|
||||||
|
@ -26,186 +135,60 @@ fn process(data: &str) -> usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map = vec![vec!['.'; n]; m];
|
let mut map = vec![vec![Tile::Ground; n]; m];
|
||||||
|
|
||||||
'outer: for mut c in ['|', '-', 'L', 'J', '7', 'F'] {
|
'outer: for c in ['-', '|', 'L', 'J', '7', 'F'] {
|
||||||
|
let mut start = true;
|
||||||
|
grid[s_x][s_y] = c;
|
||||||
let mut sx = s_x;
|
let mut sx = s_x;
|
||||||
let mut sy = s_y;
|
let mut sy = s_y;
|
||||||
let (mut px, mut py) = (s_x, s_y);
|
|
||||||
let mut start = true;
|
|
||||||
|
|
||||||
grid[sx][sy] = c;
|
let mut direction = Direction::Unknown;
|
||||||
|
let mut local_map = map.clone();
|
||||||
|
|
||||||
let mut tmp_map = map.clone();
|
loop {
|
||||||
|
if !start && (sx == s_x && sy == s_y) {
|
||||||
while start || !(sx == s_x && sy == s_y) {
|
break;
|
||||||
|
}
|
||||||
start = false;
|
start = false;
|
||||||
|
|
||||||
tmp_map[sx][sy] = c;
|
local_map[sx][sy] = Tile::from(grid[sx][sy]);
|
||||||
|
// what we need to figure out the next step
|
||||||
|
// 1. The current character
|
||||||
|
// 2. Direction we are headed in
|
||||||
|
// 3. the potential next character. since it's possible we jump to an un jumpable
|
||||||
|
// character
|
||||||
|
|
||||||
match c {
|
let (new_direction, valid_pipes) = next_direction(grid[sx][sy], &direction);
|
||||||
'|' => {
|
|
||||||
if sx > 0
|
|
||||||
&& !(sx - 1 == px && sy == py)
|
|
||||||
&& ['7', 'F', '|', 'S'].contains(&grid[sx - 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1
|
|
||||||
&& !(sx + 1 == px && sy == py)
|
|
||||||
&& ['L', 'J', '|', 'S'].contains(&grid[sx + 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'F' => {
|
|
||||||
if sy < n - 1
|
|
||||||
&& !(sx == px && sy + 1 == py)
|
|
||||||
&& ['-', 'J', '7', 'S'].contains(&grid[sx][sy + 1])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1
|
|
||||||
&& !(sx + 1 == px && px == py)
|
|
||||||
&& ['L', 'J', '|', 'S'].contains(&grid[sx + 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'-' => {
|
let (x, y) = match new_direction {
|
||||||
if sy > 0
|
Direction::Unknown => unreachable!(),
|
||||||
&& !(sx == px && sy - 1 == py)
|
Direction::North => (-1, 0),
|
||||||
&& ['L', 'F', '-', 'S'].contains(&grid[sx][sy - 1])
|
Direction::South => (1, 0),
|
||||||
{
|
Direction::East => (0, 1),
|
||||||
px = sx;
|
Direction::West => (0, -1),
|
||||||
py = sy;
|
};
|
||||||
sy -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sy < n - 1
|
|
||||||
&& !(sx == px && sy + 1 == py)
|
|
||||||
&& ['J', '7', '-', 'S'].contains(&grid[sx][sy + 1])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'7' => {
|
let p = sx as i32 + x;
|
||||||
if sy > 0
|
let q = sy as i32 + y;
|
||||||
&& !(sx == px && sy - 1 == py)
|
if p < 0 || q < 0 || p >= m as i32 || q >= n as i32 {
|
||||||
&& ['L', 'F', '-', 'S'].contains(&grid[sx][sy - 1])
|
continue 'outer;
|
||||||
{
|
}
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx < m - 1
|
|
||||||
&& !(sx + 1 == px && sy == py)
|
|
||||||
&& ['L', 'J', '|', 'S'].contains(&grid[sx + 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'J' => {
|
let next_pipe = Tile::from(grid[p as usize][q as usize]);
|
||||||
if sy > 0
|
if valid_pipes & next_pipe as u8 > 0 {
|
||||||
&& !(sx == px && sy - 1 == py)
|
sx = p as usize;
|
||||||
&& ['L', 'F', '-', 'S'].contains(&grid[sx][sy - 1])
|
sy = q as usize;
|
||||||
{
|
direction = new_direction;
|
||||||
px = sx;
|
} else {
|
||||||
py = sy;
|
continue 'outer;
|
||||||
sy -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sx > 0
|
|
||||||
&& !(sx - 1 == px && sy == py)
|
|
||||||
&& ['7', 'F', '|', 'S'].contains(&grid[sx - 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'L' => {
|
|
||||||
if sx > 0
|
|
||||||
&& !(sx - 1 == px && sy == py)
|
|
||||||
&& ['7', 'F', '|', 'S'].contains(&grid[sx - 1][sy])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sx -= 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else if sy < n - 1
|
|
||||||
&& !(sx == px && sy + 1 == py)
|
|
||||||
&& ['J', '7', '-', 'S'].contains(&grid[sx][sy + 1])
|
|
||||||
{
|
|
||||||
px = sx;
|
|
||||||
py = sy;
|
|
||||||
sy += 1;
|
|
||||||
c = grid[sx][sy];
|
|
||||||
} else {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'.' => continue 'outer,
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match (
|
map = local_map;
|
||||||
sx as i32 - px as i32,
|
|
||||||
sy as i32 - py as i32,
|
|
||||||
grid[px][py],
|
|
||||||
grid[sx][sy],
|
|
||||||
) {
|
|
||||||
(-1, 0, 'J', 'F') => (),
|
|
||||||
(-1, 0, '|', '|') => {
|
|
||||||
if sx == 0 || sx == m - 1 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(-1, 0, '|', '7') => (),
|
|
||||||
(-1, 0, '|', 'F') => (),
|
|
||||||
(0, -1, 'J', 'L') => (),
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if sx == s_x && sy == s_y {
|
|
||||||
map = tmp_map;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut nmap = vec![vec!['.'; n * 2]; m * 2];
|
let mut nmap = vec![vec![Tile::Ground; n * 2]; m * 2];
|
||||||
|
|
||||||
for (i, line) in map.iter().enumerate() {
|
for (i, line) in map.iter().enumerate() {
|
||||||
for (j, c) in line.iter().enumerate() {
|
for (j, c) in line.iter().enumerate() {
|
||||||
|
@ -213,29 +196,34 @@ fn process(data: &str) -> usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Tile::*;
|
||||||
for line in nmap.iter_mut() {
|
for line in nmap.iter_mut() {
|
||||||
for j in 0..2 * n - 2 {
|
for j in 0..2 * n - 2 {
|
||||||
if ['F', 'L', '-'].contains(&line[j]) && ['J', '7', '-'].contains(&line[j + 2]) {
|
if (line[j] as u8 & (F as u8 | L as u8 | Horizontal as u8)) > 0
|
||||||
line[j + 1] = '-';
|
&& (line[j + 2] as u8 & (J as u8 | Seven as u8 | Horizontal as u8)) > 0
|
||||||
|
{
|
||||||
|
line[j + 1] = Horizontal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for j in 0..n * 2 {
|
for j in 0..n * 2 {
|
||||||
for i in 0..m * 2 - 2 {
|
for i in 0..m * 2 - 2 {
|
||||||
if ['F', '7', '|'].contains(&nmap[i][j]) && ['L', 'J', '|'].contains(&nmap[i + 2][j]) {
|
if (nmap[i][j] as u8 & (F as u8 | Seven as u8 | Vertical as u8)) > 0
|
||||||
nmap[i + 1][j] = '|';
|
&& (nmap[i + 2][j] as u8 & (L as u8 | J as u8 | Vertical as u8)) > 0
|
||||||
|
{
|
||||||
|
nmap[i + 1][j] = Vertical;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for j in 0..2 * n {
|
for j in 0..2 * n {
|
||||||
if nmap[0][j] == '.' {
|
if nmap[0][j] == Ground {
|
||||||
flood_fill(&mut nmap, 0, j, 'X');
|
flood_fill(&mut nmap, 0, j, X);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut out = vec![vec!['.'; n]; m];
|
let mut out = vec![vec![Tile::Ground; n]; m];
|
||||||
|
|
||||||
for (i, line) in nmap.iter().enumerate() {
|
for (i, line) in nmap.iter().enumerate() {
|
||||||
if i % 2 != 0 {
|
if i % 2 != 0 {
|
||||||
|
@ -253,7 +241,7 @@ fn process(data: &str) -> usize {
|
||||||
|
|
||||||
for line in out.into_iter() {
|
for line in out.into_iter() {
|
||||||
for c in line.into_iter() {
|
for c in line.into_iter() {
|
||||||
if c == '.' {
|
if c == Tile::Ground {
|
||||||
answer += 1;
|
answer += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,7 +250,7 @@ fn process(data: &str) -> usize {
|
||||||
answer
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flood_fill(map: &mut Vec<Vec<char>>, i: usize, j: usize, fill_with: char) {
|
fn flood_fill(map: &mut Vec<Vec<Tile>>, i: usize, j: usize, fill_with: Tile) {
|
||||||
let m = map.len();
|
let m = map.len();
|
||||||
let n = map[0].len();
|
let n = map[0].len();
|
||||||
const DIRS: [[i32; 2]; 4] = [[0, 1], [0, -1], [-1, 0], [1, 0]];
|
const DIRS: [[i32; 2]; 4] = [[0, 1], [0, -1], [-1, 0], [1, 0]];
|
||||||
|
@ -271,7 +259,7 @@ fn flood_fill(map: &mut Vec<Vec<char>>, i: usize, j: usize, fill_with: char) {
|
||||||
stack.push((i, j));
|
stack.push((i, j));
|
||||||
|
|
||||||
while let Some((sx, sy)) = stack.pop() {
|
while let Some((sx, sy)) = stack.pop() {
|
||||||
if map[sx][sy] != '.' {
|
if map[sx][sy] != Tile::Ground {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +290,7 @@ fn main() {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn part1(b: &mut test::Bencher) {
|
fn part1(b: &mut test::Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let v = process(INPUTS[1]);
|
let v = process(INPUTS[INPUTS.len() - 1]);
|
||||||
test::black_box(v);
|
test::black_box(v);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
.F----7F7F7F7F-7....
|
FF7FSF7F7F7F7F7F---7
|
||||||
.|F--7||||||||FJ....
|
L|LJ||||||||||||F--J
|
||||||
.||.FJ||||||||L7....
|
FL-7LJLJ||||||LJL-77
|
||||||
FJL7L7LJLJ||LJ.L-7..
|
F--JF--7||LJLJ7F7FJ-
|
||||||
L--J.L7...LJS7F-7L7.
|
L---JF-JLJ.||-FJLJJ7
|
||||||
....F-J..F7FJ|L7L7L7
|
|F|F-JF---7F7-L7L|7|
|
||||||
....L7.F7||L7|.L7L7|
|
|FFJF7L7F-JF7|JL---7
|
||||||
.....|FJLJ|FJ|F7|.LJ
|
7-L-JL7||F7|L7F-7F7|
|
||||||
....FJL-7.||.||||...
|
L.L7LFJ|||||FJL7||LJ
|
||||||
....L---J.LJ.LJLJ...
|
L7JLJL-JLJLJL--JLJ.L
|
Loading…
Reference in New Issue
Block a user