Skip to content

Commit

Permalink
Improvement: Year 2016: Day 13: Now using a common BFS algorithm ever…
Browse files Browse the repository at this point in the history
…ywhere
  • Loading branch information
joshleaves committed Mar 21, 2024
1 parent 27d5e1a commit 00fe517
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 65 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Of note:
- The changelog 2015.5.2 has been rewritten from each commit content.
- This file may be amended entirely in the future to adhere to the [GNU Changelog style](https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs)

## [2016.17.2]
### Changed
- Exercise for 2016, day 13, now uses the [BreadthFirstSearch](src/bfs.rs) lib.

## [2016.17.1]
### Added
- Solved [exercice for 2016, day 17](src/year_2016/17.rs).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "advent-rs"
version = "2016.17.1"
version = "2016.17.2"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down
2 changes: 2 additions & 0 deletions NOTES_2016.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ Another thing of note is that if you know how to optimize your loop-down, you ca
## Day 17: Two Steps Forward

A big part of this day was bout building a [BreadthFirstSearch library](src/bfs.rs) that would be flexible enough to reuse in other exercises, since there are SO MANY in this year.

There was some confusion between all the generics, abstractions, and types, especially since this day got some strange rules (storing together position+path) but in the end, I think I got it, and implementing it on day 13 (which only got a position) was really fast, and execution time got faster too.
4 changes: 2 additions & 2 deletions src/bfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ where
starting: POS,
pub ending: Option<POS>,
queue: VecDeque<(POS, usize)>,
visited: HashSet<POS>,
pub visited: HashSet<POS>,
pub depth: usize,
next_moves: NM,
}
Expand Down Expand Up @@ -59,7 +59,7 @@ where
}

pub fn traverse_until_depth(&mut self, target_depth: usize) -> &mut Self {
self.traverse(|_position, depth| depth == target_depth, true)
self.traverse(|_position, depth| depth > target_depth, true)
}

pub fn traverse_until_position(&mut self, target_position: POS) -> &mut Self {
Expand Down
70 changes: 16 additions & 54 deletions src/year_2016/day_13.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,4 @@
use std::collections::HashSet;
use std::collections::VecDeque;

enum PositionOrCount {
Position((usize, usize)),
Count(u8),
}

impl PositionOrCount {
fn reached_position(&self, reach: (usize, usize)) -> bool {
match self {
PositionOrCount::Position(target) => *target == reach,
PositionOrCount::Count(_) => false,
}
}

fn reached_count(&self, steps_count: u8) -> bool {
match self {
PositionOrCount::Position(_) => false,
PositionOrCount::Count(count) => steps_count > *count,
}
}
}
use crate::bfs::BreadthFirstSearch;

fn cell_is_wall(favorite: usize, position: (usize, usize)) -> bool {
let x = position.0;
Expand All @@ -29,42 +7,22 @@ fn cell_is_wall(favorite: usize, position: (usize, usize)) -> bool {
return value.count_ones() % 2 == 1;
}

fn next_moves(position: (usize, usize)) -> Vec<(usize, usize)> {
fn next_moves(favorite: usize, position: (usize, usize)) -> Vec<(usize, usize)> {
let mut new_moves: Vec<(usize, usize)> = vec![];
if position.0 > 0 {
if position.0 > 0 && !cell_is_wall(favorite, (position.0 - 1, position.1)) {
new_moves.push((position.0 - 1, position.1));
}
new_moves.push((position.0 + 1, position.1));
if position.1 > 0 {
if !cell_is_wall(favorite, (position.0 + 1, position.1)) {
new_moves.push((position.0 + 1, position.1));
}
if position.1 > 0 && !cell_is_wall(favorite, (position.0, position.1 - 1)) {
new_moves.push((position.0, position.1 - 1));
}
new_moves.push((position.0, position.1 + 1));

new_moves
}

fn traverse_until(favorite: usize, reach_condition: PositionOrCount) -> u8 {
let mut visited: HashSet<(usize, usize)> = HashSet::from([(1, 1)]);
let mut queue: VecDeque<((usize, usize), u8)> = VecDeque::from([((1, 1), 0)]);

while let Some((position, depth)) = queue.pop_front() {
if reach_condition.reached_position(position) {
return depth;
}
if reach_condition.reached_count(depth) {
return visited.len() as u8;
}

visited.insert(position);
for next_move in next_moves(position) {
if visited.contains(&next_move) || cell_is_wall(favorite, next_move) {
continue;
}
queue.push_back((next_move, depth + 1));
}
if !cell_is_wall(favorite, (position.0, position.1 + 1)) {
new_moves.push((position.0, position.1 + 1));
}

0
new_moves
}

pub fn day_13_v1(input: impl Into<String>) -> u8 {
Expand All @@ -73,16 +31,20 @@ pub fn day_13_v1(input: impl Into<String>) -> u8 {
let favorite = input_parts[0].parse::<usize>().unwrap();
let reach_x = input_parts[1].parse::<usize>().unwrap();
let reach_y = input_parts[2].parse::<usize>().unwrap();
let mut bfs = BreadthFirstSearch::new((1, 1), |position| next_moves(favorite, position));
bfs.traverse_until_position((reach_x, reach_y));

traverse_until(favorite, PositionOrCount::Position((reach_x, reach_y)))
bfs.depth as u8
}

pub fn day_13_v2(input: impl Into<String>) -> u8 {
let binding = input.into();
let input_parts: Vec<_> = binding.split(",").collect();
let favorite = input_parts[0].parse::<usize>().unwrap();
let mut bfs = BreadthFirstSearch::new((1, 1), |position| next_moves(favorite, position));
bfs.traverse_until_depth(50);

traverse_until(favorite, PositionOrCount::Count(50))
bfs.visited.len() as u8
}

solvable!(day_13, day_13_v1, day_13_v2, u8);
Expand Down
12 changes: 4 additions & 8 deletions src/year_2016/day_17.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl Day17Position {
}
}

pub fn next_moves_for_hasher(&self, mut hasher: CoreWrapper<Md5Core>) -> Vec<Self> {
pub fn next_moves(&self, mut hasher: CoreWrapper<Md5Core>) -> Vec<Self> {
hasher.update(self.path.clone());
let positions: &[u8] = &hasher.finalize()[0..=1];
let mut next_moves = vec![];
Expand Down Expand Up @@ -101,9 +101,7 @@ pub fn day_17_v1(input: impl Into<String>) -> String {
let mut hasher = Md5::new();
hasher.update(input.into().trim_end());
let starter = Day17Position::new((0, 0));
let mut bfs = BreadthFirstSearch::new(starter, |curpos| {
curpos.next_moves_for_hasher(hasher.clone())
});
let mut bfs = BreadthFirstSearch::new(starter, |curpos| curpos.next_moves(hasher.clone()));
bfs.traverse_until(|position| position.position == (3, 3));

bfs.ending.unwrap().path
Expand All @@ -113,9 +111,7 @@ pub fn day_17_v2(input: impl Into<String>) -> String {
let mut hasher = Md5::new();
hasher.update(input.into().trim_end());
let starter = Day17Position::new((0, 0));
let mut bfs = BreadthFirstSearch::new(starter, |curpos| {
curpos.next_moves_for_hasher(hasher.clone())
});
let mut bfs = BreadthFirstSearch::new(starter, |curpos| curpos.next_moves(hasher.clone()));
bfs.longest_path_until(|position| position.position == (3, 3));

bfs.depth.to_string()
Expand All @@ -135,12 +131,12 @@ mod tests {
("ulqzkmiv", "DRURDRUDDLLDLUURRDULRLDUUDDDRR"),
];
for (sample, result) in sample_one {
println!("TEST => {}", sample);
assert_eq!(day_17_v1(sample), result);
}
}

#[test]
#[ignore = "Too slow for CI"]
fn works_with_samples_v2() {
let sample_two: [(&str, &str); 3] = [
("ihgpwlah", "370"),
Expand Down

0 comments on commit 00fe517

Please sign in to comment.