mirror of
https://github.com/mx42/aoc2024.rs.git
synced 2026-01-14 05:49:53 +01:00
feat: day 6 part 1
This commit is contained in:
@@ -21,13 +21,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
|
||||
|
||||
| Day | Part 1 | Part 2 |
|
||||
| :---: | :---: | :---: |
|
||||
| [Day 1](./src/bin/01.rs) | `72.0µs` | `76.8µs` |
|
||||
| [Day 2](./src/bin/02.rs) | `215.6µs` | `371.6µs` |
|
||||
| [Day 3](./src/bin/03.rs) | `652.5µs` | `736.7µs` |
|
||||
| [Day 4](./src/bin/04.rs) | `5.6ms` | `2.4ms` |
|
||||
| [Day 5](./src/bin/05.rs) | `3.7ms` | `9.7ms` |
|
||||
| [Day 6](./src/bin/06.rs) | `5.4ms` | `-` |
|
||||
|
||||
**Total: 23.53ms**
|
||||
**Total: 5.40ms**
|
||||
<!--- benchmarking table --->
|
||||
|
||||
---
|
||||
|
||||
10
data/examples/06.txt
Normal file
10
data/examples/06.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
....#.....
|
||||
.........#
|
||||
..........
|
||||
..#.......
|
||||
.......#..
|
||||
..........
|
||||
.#..^.....
|
||||
........#.
|
||||
#.........
|
||||
......#...
|
||||
248
src/bin/06.rs
Normal file
248
src/bin/06.rs
Normal file
@@ -0,0 +1,248 @@
|
||||
advent_of_code::solution!(6);
|
||||
|
||||
use std::iter::successors;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum Dir {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
fn to_vec(&self) -> (i8, i8) {
|
||||
match self {
|
||||
Dir::Up => ( 0, -1),
|
||||
Dir::Right => ( 1, 0),
|
||||
Dir::Down => ( 0, 1),
|
||||
Dir::Left => (-1, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn rotate90(&self) -> Self {
|
||||
match self {
|
||||
Dir::Up => Dir::Right,
|
||||
Dir::Right => Dir::Down,
|
||||
Dir::Down => Dir::Left,
|
||||
Dir::Left => Dir::Up,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Pos {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
fn init(x: usize, y: usize) -> Pos {
|
||||
Pos { x, y }
|
||||
}
|
||||
|
||||
fn move_towards(&self, v: (i8, i8), max: &Self) -> Option<Self> {
|
||||
let new_x: isize = self.x as isize + v.0 as isize;
|
||||
let new_y: isize = self.y as isize + v.1 as isize;
|
||||
if new_x >= 0
|
||||
&& (new_x as usize) < max.x
|
||||
&& new_y >= 0
|
||||
&& (new_y as usize) < max.y {
|
||||
Some(Pos { x: new_x as usize, y: new_y as usize })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_at_limit(&self, max: &Self) -> bool {
|
||||
self.x == max.x - 1|| self.y == max.y - 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct Guard {
|
||||
pos: Pos,
|
||||
facing: Dir,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Guard {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self.facing {
|
||||
Dir::Up => write!(f, "^"),
|
||||
Dir::Left => write!(f, "<"),
|
||||
Dir::Right => write!(f, ">"),
|
||||
Dir::Down => write!(f, "V"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State {
|
||||
walls: Vec<Pos>,
|
||||
walked: Vec<Guard>,
|
||||
guard: Guard,
|
||||
map_size: Pos,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
writeln!(f, "Size: {:?}", self.map_size)?;
|
||||
for y in 0..self.map_size.y {
|
||||
for x in 0..self.map_size.x {
|
||||
let pos = Pos { x, y };
|
||||
if self.walls.contains(&pos) {
|
||||
write!(f, "#")?;
|
||||
continue;
|
||||
}
|
||||
// screw the cpu
|
||||
let match_walk = self
|
||||
.walked.clone()
|
||||
.into_iter()
|
||||
.filter(|g| g.pos == pos)
|
||||
.collect::<Vec<_>>();
|
||||
match match_walk.len() {
|
||||
0 => write!(f, ".")?,
|
||||
1 => write!(f, "{:?}", match_walk[0])?,
|
||||
_ => write!(f, "*")?,
|
||||
}
|
||||
}
|
||||
writeln!(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl State {
|
||||
fn step(self) -> Option<Self> {
|
||||
if self.is_last_step() {
|
||||
return None;
|
||||
}
|
||||
let guard_walk_direction = self.guard.facing.to_vec();
|
||||
let guard_walk = successors(
|
||||
Some(self.guard.pos),
|
||||
|pos| {
|
||||
if let Some(new_pos) = pos.move_towards(guard_walk_direction, &self.map_size) {
|
||||
if !self.walls.contains(&new_pos) {
|
||||
return Some(new_pos)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
)
|
||||
.collect::<Vec<Pos>>();
|
||||
let guard_new_pos = guard_walk.last().unwrap().clone();
|
||||
let mut walked: Vec<Guard> = self.walked.clone();
|
||||
walked.extend(
|
||||
guard_walk.iter().map(|p| Guard { pos: p.clone(), facing: self.guard.facing })
|
||||
);
|
||||
|
||||
Some(Self {
|
||||
guard: Guard {
|
||||
pos: guard_new_pos,
|
||||
facing: self.guard.facing.rotate90(),
|
||||
},
|
||||
walked: walked,
|
||||
..self
|
||||
})
|
||||
}
|
||||
|
||||
fn is_last_step(&self) -> bool {
|
||||
self.guard.pos.is_at_limit(&self.map_size)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_line(line: &str, line_nb: usize) -> (Vec<Pos>, Option<Pos>) {
|
||||
line
|
||||
.chars()
|
||||
.enumerate()
|
||||
.fold(
|
||||
(Vec::<Pos>::new(), None),
|
||||
|(mut wpos, gpos), (pos, chr)| match chr {
|
||||
'#' => {
|
||||
wpos.push(Pos::init(pos, line_nb));
|
||||
(wpos, gpos)
|
||||
},
|
||||
'^' => {
|
||||
(wpos, Some(Pos::init(pos, line_nb)))
|
||||
},
|
||||
_ => (wpos, gpos)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> State {
|
||||
let input = input.lines().collect::<Vec<_>>();
|
||||
let size = Pos::init(
|
||||
input[0].len(),
|
||||
input.len()
|
||||
);
|
||||
let data = input
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(nb, line)| parse_line(line, nb))
|
||||
.fold(
|
||||
(Vec::<Pos>::new(), None),
|
||||
|(mut gl_wpos, gl_gpos), (wpos, gpos)| {
|
||||
gl_wpos.extend(wpos);
|
||||
match gpos {
|
||||
Some(_) => (gl_wpos, gpos),
|
||||
_ => (gl_wpos, gl_gpos),
|
||||
}
|
||||
}
|
||||
);
|
||||
if data.1.is_none() {
|
||||
panic!("Guard position not found?!");
|
||||
}
|
||||
let guard: Guard = Guard {
|
||||
pos: data.1.unwrap(),
|
||||
facing: Dir::Up
|
||||
};
|
||||
State {
|
||||
walls: data.0,
|
||||
guard: guard.clone(),
|
||||
walked: vec![guard],
|
||||
map_size: size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_one(input: &str) -> Option<usize> {
|
||||
let state = parse_input(input);
|
||||
let last_state = successors(
|
||||
Some(state),
|
||||
|s| s.clone().step())
|
||||
.last().unwrap();
|
||||
// println!("{:?}", last_state);
|
||||
let mut visited = last_state
|
||||
.walked
|
||||
.iter()
|
||||
.map(|g| &g.pos)
|
||||
.collect::<Vec<&Pos>>();
|
||||
visited.sort();
|
||||
visited.dedup();
|
||||
|
||||
Some(visited.len())
|
||||
}
|
||||
|
||||
pub fn part_two(input: &str) -> Option<u32> {
|
||||
let state = parse_input(input);
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_part_one() {
|
||||
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, Some(41));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_two() {
|
||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, None);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user