diff --git a/src/day6.rs b/src/day6.rs new file mode 100644 index 0000000..7d66a31 --- /dev/null +++ b/src/day6.rs @@ -0,0 +1,124 @@ +use std::collections::HashSet; + +#[derive(PartialEq, Eq)] +enum Position { + Occupied, + Free, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +enum Direction { + Up, + Down, + Left, + Right, +} + +impl Direction { + fn rotate(self) -> Self { + match self { + Self::Up => Self::Right, + Self::Right => Self::Down, + Self::Down => Self::Left, + Self::Left => Self::Up, + } + } + + fn next( + self, + mut current: (usize, usize), + dimentions: (usize, usize), + ) -> Option<(usize, usize)> { + match self { + Self::Up => current.0 = current.0.checked_sub(1)?, + Self::Down => current.0 += 1, + Self::Left => current.1 = current.1.checked_sub(1)?, + Self::Right => current.1 += 1, + } + if current.0 >= dimentions.0 || current.1 >= dimentions.1 { + return None; + } + Some(current) + } +} + +fn parse_board(data: &str) -> (Vec>, (usize, usize)) { + let mut position = None; + let board = data + .lines() + .enumerate() + .map(|(i, line)| { + line.bytes() + .enumerate() + .map(|(j, b)| match b { + b'#' => Position::Occupied, + b'.' => Position::Free, + b'^' => { + position = Some((i, j)); + Position::Free + } + byte => unreachable!("{}", byte as char), + }) + .collect() + }) + .collect(); + (board, position.expect("User pos not found")) +} + +fn get_visited(board: &[Vec], mut pos: (usize, usize)) -> HashSet<(usize, usize)> { + let mut visited = HashSet::new(); + let mut direction = Direction::Up; + let dimentions = (board.len(), board[1].len()); + loop { + let Some(p) = direction.next(pos, dimentions) else { + break; + }; + if board[p.0][p.1] == Position::Occupied { + direction = direction.rotate(); + continue; + } + pos = p; + visited.insert(p); + } + visited +} + +pub fn task1() { + let (board, pos) = parse_board(&std::fs::read_to_string("input.txt").unwrap()); + let mut visited = get_visited(&board, pos); + visited.insert(pos); + println!("{}", visited.len()); +} + +fn is_loop(board: &[Vec], mut pos: (usize, usize)) -> bool { + let mut visited = HashSet::new(); + let mut direction = Direction::Up; + let dimentions = (board.len(), board[1].len()); + loop { + let Some(p) = direction.next(pos, dimentions) else { + return false; + }; + if board[p.0][p.1] == Position::Occupied { + direction = direction.rotate(); + continue; + } + pos = p; + if !visited.insert((pos, direction)) { + return true; + } + } +} + +pub fn task2() { + let (mut board, pos) = parse_board(&std::fs::read_to_string("input.txt").unwrap()); + let visited = get_visited(&board, pos); + let mut c: usize = 0; + for (a, b) in visited { + board[a][b] = Position::Occupied; + if is_loop(&board, pos) { + c += 1; + } + board[a][b] = Position::Free; + } + println!("{c}"); +} diff --git a/src/main.rs b/src/main.rs index 7c92b89..e989070 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod day2; mod day3; mod day4; mod day5; +mod day6; use std::{ fs::File, @@ -20,6 +21,6 @@ fn parse_line(line: &str, pattern: char) -> impl Iterator + '_ { } fn main() { - day5::task1(); - day5::task2(); + day6::task1(); + day6::task2(); }