From 65ada73bf439168cfa1d7a90ee6dbacc622ab729 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Fri, 6 Dec 2024 11:09:22 +0200 Subject: [PATCH] feat: day6 --- input/day6/example | 10 ++ src/day6/mod.rs | 227 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 9 ++ 3 files changed, 246 insertions(+) create mode 100644 input/day6/example create mode 100644 src/day6/mod.rs diff --git a/input/day6/example b/input/day6/example new file mode 100644 index 0000000..a4eb402 --- /dev/null +++ b/input/day6/example @@ -0,0 +1,10 @@ +....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... diff --git a/src/day6/mod.rs b/src/day6/mod.rs new file mode 100644 index 0000000..2ecc27b --- /dev/null +++ b/src/day6/mod.rs @@ -0,0 +1,227 @@ +use std::{ + fs::File, + io::{BufRead, BufReader}, + path::Path, +}; + +pub fn solve(input: &Path) -> anyhow::Result<()> { + println!("part one: {}", part_one(input)?); + println!("part two: {}", part_two(input)?); + + Ok(()) +} + +#[derive(Default, Clone)] +struct Pos { + x: usize, + y: usize, + visited: bool, + obstacle: bool, +} + +#[derive(Clone, Debug)] +struct Guard { + x: usize, + y: usize, + direction: Direction, +} + +impl Guard { + fn turn(&mut self) { + match self.direction { + Direction::North => self.direction = Direction::East, + Direction::East => self.direction = Direction::South, + Direction::South => self.direction = Direction::West, + Direction::West => self.direction = Direction::North, + } + } + + fn move_forward(&mut self) { + match self.direction { + Direction::North => self.y -= 1, + Direction::East => self.x += 1, + Direction::South => self.y += 1, + Direction::West => self.x -= 1, + } + } +} + +#[derive(Clone, Debug)] +enum Direction { + North, + East, + South, + West, +} + +fn part_one(input: &Path) -> anyhow::Result { + let reader = BufReader::new(File::open(input)?); + + let mut map: Vec> = vec![]; + let mut guard: Option = None; + for (y, line) in reader.lines().enumerate() { + let mut row = vec![]; + for (x, c) in line?.char_indices() { + match c { + '.' => row.push(Pos { + x, + y, + ..Default::default() + }), + '#' => row.push(Pos { + x, + y, + obstacle: true, + ..Default::default() + }), + '^' => { + row.push(Pos { + x, + y, + visited: true, + ..Default::default() + }); + guard = Some(Guard { + x, + y, + direction: Direction::North, + }); + } + _ => panic!("invalid map"), + } + } + map.push(row); + } + let mut guard = guard.unwrap(); + + loop { + //print_map(&map); + if let Some(in_front) = get_in_front(&guard, &mut map) { + if in_front.obstacle { + guard.turn(); + } else { + in_front.visited = true; + guard.move_forward(); + } + } else { + break; + } + //std::thread::sleep(std::time::Duration::from_millis(50)); + } + + //print_map(&map); + + Ok(map.iter().flatten().filter(|p| p.visited).count() as i32) +} + +fn get_in_front<'a>(guard: &'a Guard, map: &'a mut [Vec]) -> Option<&'a mut Pos> { + match guard.direction { + Direction::North => match map.get_mut(if guard.y == 0 { + return None; + } else { + guard.y - 1 + }) { + Some(row) => row.get_mut(guard.x), + None => None, + }, + Direction::East => match map.get_mut(guard.y) { + Some(row) => row.get_mut(guard.x + 1), + None => None, + }, + Direction::South => match map.get_mut(guard.y + 1) { + Some(row) => row.get_mut(guard.x), + None => None, + }, + Direction::West => match map.get_mut(guard.y) { + Some(row) => row.get_mut(if guard.x == 0 { + return None; + } else { + guard.x - 1 + }), + None => None, + }, + } +} + +fn print_map(map: &[Vec]) { + for row in map { + for pos in row { + if pos.obstacle { + print!("# "); + } else if pos.visited { + print!("X "); + } else { + print!(". "); + } + } + println!(); + } +} + +fn part_two(input: &Path) -> anyhow::Result { + let reader = BufReader::new(File::open(input)?); + + let mut map: Vec> = vec![]; + let mut guard: Option = None; + for (y, line) in reader.lines().enumerate() { + let mut row = vec![]; + for (x, c) in line?.char_indices() { + match c { + '.' => row.push(Pos { + x, + y, + ..Default::default() + }), + '#' => row.push(Pos { + x, + y, + obstacle: true, + ..Default::default() + }), + '^' => { + row.push(Pos { + x, + y, + visited: true, + ..Default::default() + }); + guard = Some(Guard { + x, + y, + direction: Direction::North, + }); + } + _ => panic!("invalid map"), + } + } + map.push(row); + } + let guard = guard.unwrap(); + + let mut block_positions = 0; + for pos in map.iter().flatten() { + let mut guard = guard.clone(); + let mut modified_map = map.clone(); + modified_map[pos.y][pos.x].obstacle = true; + let start_time = std::time::Instant::now(); + loop { + if let Some(in_front) = get_in_front(&guard, &mut modified_map) { + if in_front.obstacle { + guard.turn(); + } else { + in_front.visited = true; + guard.move_forward(); + } + } else { + break; + } + + if start_time.elapsed().as_millis() >= 1 { + block_positions += 1; + break; + } + } + } + + Ok(block_positions) +} diff --git a/src/main.rs b/src/main.rs index e03647d..f15eca4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![allow(clippy::comparison_chain)] #![allow(clippy::while_let_loop)] #![allow(clippy::needless_range_loop)] +#![allow(dead_code)] use std::path::PathBuf; use clap::{Parser, Subcommand}; @@ -10,6 +11,7 @@ mod day2; mod day3; mod day4; mod day5; +mod day6; #[derive(Parser)] struct Args { @@ -39,6 +41,10 @@ enum DayArgs { #[arg(short)] input: PathBuf, }, + Day6 { + #[arg(short)] + input: PathBuf, + }, } fn main() -> anyhow::Result<()> { @@ -60,6 +66,9 @@ fn main() -> anyhow::Result<()> { DayArgs::Day5 { input } => { day5::solve(&input)?; } + DayArgs::Day6 { input } => { + day6::solve(&input)?; + } } Ok(()) -- 2.44.1