Skip to content

Commit

Permalink
Year 2016: Day 22
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 21, 2024
1 parent 71e6b61 commit 69bf158
Show file tree
Hide file tree
Showing 10 changed files with 1,156 additions and 6 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.22.1]
### Added
- Solved [exercice for 2016, day 22](src/year_2016/22.rs).

## [2016.21.1]
### Added
- Solved [exercice for 2016, day 21](src/year_2016/21.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.21.1"
version = "2016.22.1"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down
4 changes: 4 additions & 0 deletions NOTES_2016.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,7 @@ One of Rust's biggest pleasure is code that compiles on the first try.
## Day 21: Scrambled Letters and Hash

I love interpreters.

## Day 22: Grid Computing

So far, my [BreadthFirstSearch library](src/bfs.rs) has saved me from rewriting a BFS from scratch twice.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ As I said, [Consistency is hard](https://github.com/joshleaves/advent-rb), and I

I'm also adding notes that may be useful if you're (like me) discovering Rust:
- [2015, complete!](NOTES_2015.md)
- [2016, up to day 21](NOTES_2016.md)
- [2016, up to day 22](NOTES_2016.md)

# Regarding style rules
I'm gonna use a mix of what `cargo fmt` does, with some stuff that feels more natural to me.
Expand Down
16 changes: 15 additions & 1 deletion benches/year_2016.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use advent_rs::year_2016::day_18;
use advent_rs::year_2016::day_19;
use advent_rs::year_2016::day_20;
use advent_rs::year_2016::day_21;
use advent_rs::year_2016::day_22;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn year_2016_day_01(c: &mut Criterion) {
Expand Down Expand Up @@ -273,6 +274,18 @@ fn year_2016_day_21(c: &mut Criterion) {
g2016_day_21.finish();
}

fn year_2016_day_22(c: &mut Criterion) {
let mut g2016_day_22 = c.benchmark_group("year_2016::day_22");
let input_year_2016_day_22 = include_str!("../inputs/year_2016/day_22_input");
g2016_day_22.bench_function("year_2016::day_22_v1", |b| {
b.iter(|| day_22::day_22_v1(black_box(input_year_2016_day_22)))
});
g2016_day_22.bench_function("year_2016::day_22_v2", |b| {
b.iter(|| day_22::day_22_v2(black_box(input_year_2016_day_22)))
});
g2016_day_22.finish();
}

criterion_group!(
benches,
year_2016_day_01,
Expand All @@ -295,6 +308,7 @@ criterion_group!(
year_2016_day_18,
year_2016_day_19,
year_2016_day_20,
year_2016_day_21
year_2016_day_21,
year_2016_day_22
);
criterion_main!(benches);
990 changes: 990 additions & 0 deletions inputs/year_2016/day_22_input

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions src/bfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::hash::Hash;

pub struct BreadthFirstSearch<POS, NM>
where
POS: Eq + Hash + Clone,
POS: Eq + Hash + Clone + std::fmt::Debug,
NM: Fn(POS) -> Vec<POS>,
{
starting: POS,
Expand All @@ -17,7 +17,7 @@ where

impl<POS, NM> BreadthFirstSearch<POS, NM>
where
POS: Eq + Hash + Clone,
POS: Eq + Hash + Clone + std::fmt::Debug,
NM: Fn(POS) -> Vec<POS>,
{
pub fn new(starting: POS, next_moves: NM) -> Self {
Expand All @@ -37,6 +37,9 @@ where
{
self.queue.push_back((self.starting.clone(), 0));
while let Some((position, depth)) = self.queue.pop_front() {
if self.visited.contains(&position) {
continue;
}
if traverse_until(&position, depth) {
self.ending = Some(position);
self.depth = depth;
Expand Down
10 changes: 10 additions & 0 deletions src/year_2016.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod day_18;
pub mod day_19;
pub mod day_20;
pub mod day_21;
pub mod day_22;

pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
if part != 1 && part != 2 {
Expand Down Expand Up @@ -51,6 +52,8 @@ pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
18 => Some(format!("{}", day_18::day_18(part, input))),
19 => Some(format!("{}", day_19::day_19(part, input))),
20 => Some(format!("{}", day_20::day_20(part, input))),
21 => Some(format!("{}", day_21::day_21(part, input))),
22 => Some(format!("{}", day_22::day_22(part, input))),
_ => None,
}
}
Expand Down Expand Up @@ -214,4 +217,11 @@ mod tests {
assert_eq!(day_21::day_21_v1(input), "gfdhebac");
assert_eq!(day_21::day_21_v2(input), "dhaegfbc");
}

#[test]
fn day_22() {
let input = include_str!("../inputs/year_2016/day_22_input");
assert_eq!(day_22::day_22_v1(input), 955);
assert_eq!(day_22::day_22_v2(input), 246);
}
}
2 changes: 1 addition & 1 deletion src/year_2016/day_17.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::bfs::BreadthFirstSearch;
use md5::{digest::core_api::CoreWrapper, Digest, Md5, Md5Core};
use std::hash::{Hash, Hasher};

#[derive(Eq, Clone)]
#[derive(Eq, Clone, Debug)]
struct Day17Position {
position: (usize, usize),
path: String,
Expand Down
125 changes: 125 additions & 0 deletions src/year_2016/day_22.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use crate::bfs::BreadthFirstSearch;
use itertools::Itertools;

struct Node {
position: (u8, u8),
size: usize,
used: usize,
available: usize,
}

impl Node {
fn new(mut input: &str) -> Self {
input = input.strip_prefix("/dev/grid/node-").unwrap();
let parts: Vec<_> = input.split_whitespace().collect();
let id_parts: Vec<_> = parts[0].split('-').collect();
let x = id_parts[0][1..].parse::<u8>().unwrap();
let y = id_parts[1][1..].parse::<u8>().unwrap();
let size = parts[1]
.strip_suffix("T")
.unwrap()
.parse::<usize>()
.unwrap();
let used = parts[2]
.strip_suffix("T")
.unwrap()
.parse::<usize>()
.unwrap();
let available = parts[3]
.strip_suffix("T")
.unwrap()
.parse::<usize>()
.unwrap();

Node {
position: (x, y),
size,
used,
available,
}
}
}

#[inline]
fn parse_nodes(input: &str) -> Vec<Node> {
input
.lines()
.filter(|line| line.starts_with('/'))
.map(|line| (Node::new(line)))
.collect_vec()
}

pub fn day_22_v1(input: impl Into<String>) -> usize {
let nodes = parse_nodes(&input.into());
let mut result: usize = 0;
for combo in nodes.iter().combinations(2) {
let lhn = combo[0];
let rhn = combo[1];
if lhn.used > 0 && lhn.used < rhn.available {
result += 1;
}
if rhn.used > 0 && rhn.used < lhn.available {
result += 1;
}
}

result
}

pub fn day_22_v2(input: impl Into<String>) -> usize {
let nodes = parse_nodes(&input.into());
let max_x = nodes.iter().map(|node| node.position.0).max().unwrap();
let max_y = nodes.iter().map(|node| node.position.1).max().unwrap();
let open_node = nodes.iter().find(|node| node.used == 0).unwrap().position;
let blacknodes = nodes
.iter()
.filter(|node| node.size > 100)
.map(|node| node.position)
.collect_vec();
let mut bfs = BreadthFirstSearch::new(open_node, |position| {
let mut results: Vec<(u8, u8)> = vec![];
if position.1 > 0 && !blacknodes.contains(&(position.0, position.1 - 1)) {
results.push((position.0, position.1 - 1));
}
if position.1 < max_y && !blacknodes.contains(&(position.0, position.1 + 1)) {
results.push((position.0, position.1 + 1));
}
if position.0 > 0 && !blacknodes.contains(&(position.0 - 1, position.1)) {
results.push((position.0 - 1, position.1));
}
if position.0 < max_x && !blacknodes.contains(&(position.0 + 1, position.1)) {
results.push((position.0 + 1, position.1));
}
results
});
bfs.traverse_until_position((max_x - 1, 0));

let mut answer = bfs.depth;
answer += 1;
answer += 5 * (max_x as usize - 1);
answer
}

solvable!(day_22, day_22_v1, day_22_v2, usize);

#[cfg(test)]
mod tests {
use super::*;

const SAMPLE: &str = "root@ebhq-gridcenter# df -h\n\
Filesystem Size Used Avail Use%\n\
/dev/grid/node-x0-y0 10T 8T 2T 80%\n\
/dev/grid/node-x0-y1 11T 6T 5T 54%\n\
/dev/grid/node-x0-y2 32T 28T 4T 87%\n\
/dev/grid/node-x1-y0 9T 7T 2T 77%\n\
/dev/grid/node-x1-y1 8T 0T 8T 0%\n\
/dev/grid/node-x1-y2 11T 7T 4T 63%\n\
/dev/grid/node-x2-y0 10T 6T 4T 60%\n\
/dev/grid/node-x2-y1 9T 8T 1T 88%\n\
/dev/grid/node-x2-y2 9T 6T 3T 66%";

#[test]
fn works_with_samples_v2() {
assert_eq!(day_22_v2(SAMPLE), 7);
}
}

0 comments on commit 69bf158

Please sign in to comment.