diff --git a/src/bin/10.rs b/src/bin/10.rs index 57f98d3..57c16ec 100644 --- a/src/bin/10.rs +++ b/src/bin/10.rs @@ -2,35 +2,30 @@ use std::collections::HashSet; 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)) -// 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 { +fn next_move(dy: isize, dx: isize, c: char) -> Option<(isize, isize)> { Some(match (dy, dx) { (1, 0) => match c { - '|' => (1, 0, ((0, 1), false), ((0, -1), false)), - 'J' => (0, -1, ((1, 1), true), ((-1, -1), false)), - 'L' => (0, 1, ((-1, 1), false), ((1, -1), true)), + '|' => (1, 0), + 'J' => (0, -1), + 'L' => (0, 1), _ => None?, }, (0, 1) => match c { - '-' => (0, 1, ((-1, 0), false), ((1, 0), false)), - '7' => (1, 0, ((-1, 1), true), ((1, -1), false)), - 'J' => (-1, 0, ((-1, -1), false), ((1, 1), true)), + '-' => (0, 1), + '7' => (1, 0), + 'J' => (-1, 0), _ => None?, }, (-1, 0) => match c { - '|' => (-1, 0, ((0, -1), false), ((0, 1), false)), - '7' => (0, -1, ((1, -1), false), ((-1, 1), true)), - 'F' => (0, 1, ((-1, -1), true), ((1, 1), false)), + '|' => (-1, 0), + '7' => (0, -1), + 'F' => (0, 1), _ => None?, }, (0, -1) => match c { - '-' => (0, -1, ((1, 0), false), ((-1, 0), false)), - 'F' => (1, 0, ((1, 1), false), ((-1, -1), true)), - 'L' => (-1, 0, ((1, -1), true), ((-1, 1), false)), + '-' => (0, -1), + 'F' => (1, 0), + 'L' => (-1, 0), _ => None?, }, _ => unreachable!(), @@ -58,24 +53,19 @@ fn parse_input(input: &str) -> (Vec>, (isize, isize)) { pub fn part_one(input: &str) -> Option { 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 { let (mut dy, mut dx) = d; let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1); let mut counter = 0; while start != (ly, lx) { - if invalid_indexing(ly, lx) { - continue 'start_dir; - } - - let p = pipes[ly as usize][lx as usize]; + let p = match pipes.get(ly as usize).and_then(|x| x.get(lx as usize)) { + Some(x) => *x, + None => continue 'start_dir, + }; match next_move(dy, dx, p) { - Some((ndy, ndx, _, _)) => (dy, dx) = (ndy, ndx), + Some((ndy, ndx)) => (dy, dx) = (ndy, ndx), None => continue 'start_dir, } @@ -89,78 +79,28 @@ pub fn part_one(input: &str) -> Option { None } -fn dfs( - starts: &HashSet<(isize, isize)>, - border: &HashSet<(isize, isize)>, - (max_y, max_x): (isize, isize), -) -> Option { - 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 { 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; - - let mut lrb = [HashSet::new(), HashSet::new(), HashSet::new()]; + let mut border = HashSet::with_capacity(pipes.len() * pipes[0].len()); 'start_dir: for d in DIRS { - for map in lrb.iter_mut() { - map.clear(); - } - - lrb[2].insert(start); + border.clear(); + border.insert(start); let (mut dy, mut dx) = d; let (mut ly, mut lx) = (start.0 + d.0, start.1 + d.1); while start != (ly, lx) { - if invalid_indexing(ly, lx) { - continue 'start_dir; - } + let p = match pipes.get(ly as usize).and_then(|x| x.get(lx as usize)) { + Some(x) => *x, + None => continue 'start_dir, + }; - let p = pipes[ly as usize][lx as usize]; match next_move(dy, dx, p) { - Some((ndx, ndy, ((lly, llx), lexpand), ((rry, rrx), rexpand))) => { + Some((ndx, ndy)) => { (dy, dx) = (ndx, ndy); - lrb[2].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)); - } + border.insert((ly, lx)); } None => continue 'start_dir, } @@ -171,7 +111,29 @@ pub fn part_two(input: &str) -> Option { 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);