solution: day 10 xray

This commit is contained in:
Matej Janezic 2023-12-10 19:23:55 +01:00
parent 0000021091
commit 000002200d
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
1 changed files with 50 additions and 88 deletions

View File

@ -2,35 +2,30 @@ use std::collections::HashSet;
const DIRS: [(isize, isize); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)]; const DIRS: [(isize, isize); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)];
// type is (output dy, output dx, (left neighbour, expand), (right neighbour, expand)) fn next_move(dy: isize, dx: isize, c: char) -> Option<(isize, isize)> {
// we need to "expand" one point into three when neighbour tile is on a curve eg.: right side of
// seven going up
type MoveMapper = (isize, isize, ((isize, isize), bool), ((isize, isize), bool));
fn next_move(dy: isize, dx: isize, c: char) -> Option<MoveMapper> {
Some(match (dy, dx) { Some(match (dy, dx) {
(1, 0) => match c { (1, 0) => match c {
'|' => (1, 0, ((0, 1), false), ((0, -1), false)), '|' => (1, 0),
'J' => (0, -1, ((1, 1), true), ((-1, -1), false)), 'J' => (0, -1),
'L' => (0, 1, ((-1, 1), false), ((1, -1), true)), 'L' => (0, 1),
_ => None?, _ => None?,
}, },
(0, 1) => match c { (0, 1) => match c {
'-' => (0, 1, ((-1, 0), false), ((1, 0), false)), '-' => (0, 1),
'7' => (1, 0, ((-1, 1), true), ((1, -1), false)), '7' => (1, 0),
'J' => (-1, 0, ((-1, -1), false), ((1, 1), true)), 'J' => (-1, 0),
_ => None?, _ => None?,
}, },
(-1, 0) => match c { (-1, 0) => match c {
'|' => (-1, 0, ((0, -1), false), ((0, 1), false)), '|' => (-1, 0),
'7' => (0, -1, ((1, -1), false), ((-1, 1), true)), '7' => (0, -1),
'F' => (0, 1, ((-1, -1), true), ((1, 1), false)), 'F' => (0, 1),
_ => None?, _ => None?,
}, },
(0, -1) => match c { (0, -1) => match c {
'-' => (0, -1, ((1, 0), false), ((-1, 0), false)), '-' => (0, -1),
'F' => (1, 0, ((1, 1), false), ((-1, -1), true)), 'F' => (1, 0),
'L' => (-1, 0, ((1, -1), true), ((-1, 1), false)), 'L' => (-1, 0),
_ => None?, _ => None?,
}, },
_ => unreachable!(), _ => unreachable!(),
@ -58,24 +53,19 @@ fn parse_input(input: &str) -> (Vec<Vec<char>>, (isize, isize)) {
pub fn part_one(input: &str) -> Option<u32> { pub fn part_one(input: &str) -> Option<u32> {
let (pipes, start) = parse_input(input); let (pipes, start) = parse_input(input);
let max_y = pipes.len() as isize;
let max_x = pipes[0].len() as isize;
let invalid_indexing = |ny, nx| ny < 0 || nx < 0 || ny >= max_y || nx >= max_x;
'start_dir: for d in DIRS { 'start_dir: for d in DIRS {
let (mut dy, mut dx) = d; let (mut dy, mut dx) = d;
let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1); let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1);
let mut counter = 0; let mut counter = 0;
while start != (ly, lx) { while start != (ly, lx) {
if invalid_indexing(ly, lx) { let p = match pipes.get(ly as usize).and_then(|x| x.get(lx as usize)) {
continue 'start_dir; Some(x) => *x,
} None => continue 'start_dir,
};
let p = pipes[ly as usize][lx as usize];
match next_move(dy, dx, p) { match next_move(dy, dx, p) {
Some((ndy, ndx, _, _)) => (dy, dx) = (ndy, ndx), Some((ndy, ndx)) => (dy, dx) = (ndy, ndx),
None => continue 'start_dir, None => continue 'start_dir,
} }
@ -89,78 +79,28 @@ pub fn part_one(input: &str) -> Option<u32> {
None None
} }
fn dfs(
starts: &HashSet<(isize, isize)>,
border: &HashSet<(isize, isize)>,
(max_y, max_x): (isize, isize),
) -> Option<u32> {
let mut queue = Vec::from_iter(starts.iter().copied());
let mut visited = HashSet::new();
let invalid_indexing = |ny, nx| ny < 0 || nx < 0 || ny >= max_y || nx >= max_x;
while let Some((ny, nx)) = queue.pop() {
if invalid_indexing(ny, nx) {
return None;
}
if visited.contains(&(ny, nx)) {
continue;
}
if border.contains(&(ny, nx)) {
continue;
}
visited.insert((ny, nx));
for (dy, dx) in DIRS {
queue.push((ny + dy, nx + dx));
}
}
Some(visited.len() as u32)
}
pub fn part_two(input: &str) -> Option<u32> { pub fn part_two(input: &str) -> Option<u32> {
let (pipes, start) = parse_input(input); let (pipes, start) = parse_input(input);
let max_y = pipes.len() as isize; let mut border = HashSet::with_capacity(pipes.len() * pipes[0].len());
let max_x = pipes[0].len() as isize;
let invalid_indexing = |ny, nx| ny < 0 || nx < 0 || ny >= max_y || nx >= max_x;
let mut lrb = [HashSet::new(), HashSet::new(), HashSet::new()];
'start_dir: for d in DIRS { 'start_dir: for d in DIRS {
for map in lrb.iter_mut() { border.clear();
map.clear(); border.insert(start);
}
lrb[2].insert(start);
let (mut dy, mut dx) = d; let (mut dy, mut dx) = d;
let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1); let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1);
while start != (ly, lx) { while start != (ly, lx) {
if invalid_indexing(ly, lx) { let p = match pipes.get(ly as usize).and_then(|x| x.get(lx as usize)) {
continue 'start_dir; Some(x) => *x,
} None => continue 'start_dir,
};
let p = pipes[ly as usize][lx as usize];
match next_move(dy, dx, p) { match next_move(dy, dx, p) {
Some((ndx, ndy, ((lly, llx), lexpand), ((rry, rrx), rexpand))) => { Some((ndx, ndy)) => {
(dy, dx) = (ndx, ndy); (dy, dx) = (ndx, ndy);
lrb[2].insert((ly, lx)); border.insert((ly, lx));
lrb[0].insert((ly + lly, lx + llx));
if lexpand {
lrb[0].insert((ly + lly, lx));
lrb[0].insert((ly, lx + llx));
}
lrb[1].insert((ly + rry, lx + rrx));
if rexpand {
lrb[1].insert((ly + rry, lx));
lrb[1].insert((ly, lx + rrx));
}
} }
None => continue 'start_dir, None => continue 'start_dir,
} }
@ -171,7 +111,29 @@ pub fn part_two(input: &str) -> Option<u32> {
break; break;
} }
dfs(&lrb[0], &lrb[2], (max_y, max_x)).or(dfs(&lrb[1], &lrb[2], (max_y, max_x))) let mut counter = 0;
for (sy, sx) in (1..pipes.len())
.map(|x| (x, 0))
.chain((0..pipes[0].len()).map(|x| (0, x)))
{
let mut inside = false;
for range in 0.. {
if let Some(c) = pipes.get(sy + range).and_then(|x| x.get(sx + range)) {
let is_border = border.contains(&((sy + range) as isize, (sx + range) as isize));
if is_border && !['7', 'L'].contains(c) {
inside = !inside;
}
if !is_border && inside {
counter += 1;
}
} else {
break;
}
}
}
Some(counter)
} }
aoc::solution!(10); aoc::solution!(10);