@@ 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<i32> {
+ let reader = BufReader::new(File::open(input)?);
+
+ let mut map: Vec<Vec<Pos>> = vec![];
+ let mut guard: Option<Guard> = 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<Pos>]) -> 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<Pos>]) {
+ 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<i32> {
+ let reader = BufReader::new(File::open(input)?);
+
+ let mut map: Vec<Vec<Pos>> = vec![];
+ let mut guard: Option<Guard> = 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)
+}
@@ 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(())