diff --git a/src/bin/10.rs b/src/bin/10.rs index 57f98d3..a100063 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,35 @@ 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 i in 1..pipes.len() { + let mut range = 0; + let mut crosses = 0; + while pipes + .get(i + range) + .and_then(|x| x.get(range)) + .is_some() + { + range += 1; + if border.contains(&((i + range) as isize, (range) as isize)) { + crosses += 1; + } + } + if crosses % 2 == 1 { + counter += 1; + } + } + + for (i, j) in pipes + .iter() + .enumerate() + .flat_map(|(i, l)| l.iter().enumerate().map(move |(j, _)| (i, j))) + .filter(|(y, x)| border.contains(&(*y as isize, *x as isize))) + { + } + + Some(counter) } aoc::solution!(10);