Skip to content

Commit

Permalink
Year 2017: Day 13
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 28, 2024
1 parent 721a9d6 commit 123bc36
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 5 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ 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)

## [2017.13.1]
### Added
- Solved [exercice for 2017, day 13](src/year_2017/13.rs).
### Changed
- Added a lot of benchmarks and optimizations.

## [2017.12.1]
### Added
- Solved [exercice for 2017, day 08](src/year_2017/08.rs).
Expand All @@ -30,9 +36,9 @@ Of note:
- Solved [exercice for 2017, day 03](src/year_2017/03.rs).
- Solved [exercice for 2017, day 04](src/year_2017/04.rs).
- Solved [exercice for 2017, day 05](src/year_2017/05.rs).
### Changes
### Changed
- Benchmarks (at least for 2017) now use `assert_eq!` to ensure that changes I do to optimize runtime don't end up breaking tests.
- More tests, more optimisations,...
- More tests, more optimizations,...

## [2016.25.2]
### Changed
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "advent-rs"
version = "2017.12.1"
version = "2017.13.1"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down Expand Up @@ -72,3 +72,6 @@ harness = false
# [[bench]]
# name = "year_2017_day_04"
# harness = false
# [[bench]]
# name = "year_2017_day_13"
# harness = false
4 changes: 4 additions & 0 deletions NOTES_2017.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ Navigating hexagons is a pain. Naive approach is to start with "only change the
## Day 12: Digital Plumber

I hate traversing trees. But you don't always have to.

## Day 13: Packet Scanners

The maths were a bit annoying on this one, and I was hoping for a specific mathematical formula that would prevent me from looping over all scenarios. I found something that felt promising and ported the code from Python, but to no avail, my original code was already faster...
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,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, complete!](NOTES_2016.md)
- [2017, up to day 12](NOTES_2017.md)
- [2017, up to day 13](NOTES_2017.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
19 changes: 18 additions & 1 deletion benches/year_2017.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use advent_rs::year_2017::day_09;
use advent_rs::year_2017::day_10;
use advent_rs::year_2017::day_11;
use advent_rs::year_2017::day_12;
use advent_rs::year_2017::day_13;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn year_2017_day_01(c: &mut Criterion) {
Expand Down Expand Up @@ -195,6 +196,21 @@ fn year_2017_day_12(c: &mut Criterion) {
g2017_day_12.finish();
}

fn year_2017_day_13(c: &mut Criterion) {
let input_day_13 = include_str!("../inputs/year_2017/day_13_input");
assert_eq!(day_13::day_13_v1(black_box(input_day_13)), 2_264);
assert_eq!(day_13::day_13_v2(black_box(input_day_13)), 3_875_838);

let mut g2017_day_13 = c.benchmark_group("year_2017::day_13");
g2017_day_13.bench_function("year_2017::day_13_v1", |b| {
b.iter(|| day_13::day_13_v1(black_box(input_day_13)))
});
g2017_day_13.bench_function("year_2017::day_13_v2", |b| {
b.iter(|| day_13::day_13_v2(black_box(input_day_13)))
});
g2017_day_13.finish();
}

criterion_group!(
benches,
year_2017_day_01,
Expand All @@ -208,6 +224,7 @@ criterion_group!(
year_2017_day_09,
year_2017_day_10,
year_2017_day_11,
year_2017_day_12
year_2017_day_12,
year_2017_day_13
);
criterion_main!(benches);
60 changes: 60 additions & 0 deletions benches/year_2017_day_13.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use advent_rs::year_2017::day_13;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use itertools::Itertools;
use std::time::Duration;

// Found here: https://colab.research.google.com/github/hhoppe/advent_of_code/blob/main/2017/advent_of_code_2017.ipynb#scrollTo=84e08a8d-ca2e-4bc7-99ca-8a29a98d0bf9&line=15&uniqifier=1
pub fn day_13_v2_sieve(input: impl Into<String>) -> u32 {
let firewalls: Vec<_> = input
.into()
.lines()
.map(|line| {
let mut tuple: (i32, i32) = line
.split(": ")
.map(|num| num.parse::<i32>().unwrap())
.collect_tuple()
.unwrap();
tuple.1 = (tuple.1 - 1) * 2;
tuple
})
.collect();

let mut delay = 0;
let chunk: i32 = 200_000;
loop {
let mut ok = vec![true; chunk as usize];
for (depth, range) in &firewalls {
let first = (-(delay as i32 + *depth as i32))
.rem_euclid(*range as i32)
.abs();
for idx in (first..chunk).step_by(*range as usize) {
ok[idx as usize] = false
}
}
if let Some(index) = ok.iter().position(|v| *v == true) {
return delay as u32 + index as u32;
}
delay += chunk as i32;
}
}

fn bench_year_2017_day_13_v2(c: &mut Criterion) {
let mut group = c.benchmark_group("year_2017::day_13_v2");
group.warm_up_time(Duration::from_millis(100));
let input = include_str!("../inputs/year_2017/day_13_input");
assert_eq!(day_13_v2_sieve(input), 3_875_838);
assert_eq!(day_13::day_13_v2(input), 3_875_838);
group.bench_with_input(BenchmarkId::new("Sieve", input.len()), input, |b, input| {
b.iter(|| day_13_v2_sieve(input))
});
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_13::day_13_v2(input)),
);

group.finish();
}

criterion_group!(bench_year_2017_day_13, bench_year_2017_day_13_v2);
criterion_main!(bench_year_2017_day_13);
43 changes: 43 additions & 0 deletions inputs/year_2017/day_13_input
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
0: 3
1: 2
2: 4
4: 4
6: 5
8: 6
10: 6
12: 8
14: 6
16: 6
18: 8
20: 12
22: 8
24: 8
26: 9
28: 8
30: 8
32: 12
34: 20
36: 10
38: 12
40: 12
42: 10
44: 12
46: 12
48: 12
50: 12
52: 12
54: 14
56: 14
58: 12
62: 14
64: 14
66: 14
68: 14
70: 14
72: 14
74: 14
76: 14
78: 14
80: 18
82: 17
84: 14
9 changes: 9 additions & 0 deletions src/year_2017.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod day_09;
pub mod day_10;
pub mod day_11;
pub mod day_12;
pub mod day_13;

pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
if part > 2 {
Expand All @@ -33,6 +34,7 @@ pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
10 => Some(day_10::day_10(part, input).to_string()),
11 => Some(day_11::day_11(part, input).to_string()),
12 => Some(day_12::day_12(part, input).to_string()),
13 => Some(day_13::day_13(part, input).to_string()),
_ => None,
}
}
Expand Down Expand Up @@ -124,4 +126,11 @@ mod tests {
assert_eq!(day_12::day_12_v1(input), 130);
assert_eq!(day_12::day_12_v2(input), 189);
}

#[test]
fn day_13() {
let input = include_str!("../inputs/year_2017/day_13_input");
assert_eq!(day_13::day_13_v1(input), 2_264);
assert_eq!(day_13::day_13_v2(input), 3_875_838);
}
}
80 changes: 80 additions & 0 deletions src/year_2017/day_13.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use itertools::Itertools;

fn parse_input(input: &str) -> Vec<(i32, i32, i32)> {
input
.lines()
.map(|line| {
let tuple: (i32, i32) = line
.split(": ")
.map(|num| num.parse::<i32>().unwrap())
.collect_tuple()
.unwrap();
(tuple.0, tuple.1, (tuple.1 - 1) * 2)
})
.collect()
}

pub fn day_13_v1(input: impl Into<String>) -> u32 {
let firewalls = parse_input(&input.into());
let mut severity: u32 = 0;
for (depth, range, position) in firewalls.iter() {
if *depth == 0 || (depth % position) == 0 {
severity += *range as u32 * *depth as u32;
}
}

severity
}

#[inline]
fn traverse_firewall(firewalls: &[(i32, i32)], delay: u32) -> bool {
for (depth, range) in firewalls.iter() {
if ((*depth as u32 + delay) % *range as u32) == 0 {
return false;
}
}
true
}

pub fn day_13_v2(input: impl Into<String>) -> u32 {
let firewalls: Vec<_> = input
.into()
.lines()
.map(|line| {
let mut tuple: (i32, i32) = line
.split(": ")
.map(|num| num.parse::<i32>().unwrap())
.collect_tuple()
.unwrap();
tuple.1 = (tuple.1 - 1) * 2;
tuple
})
.collect();
let mut delay = 0;
while !traverse_firewall(&firewalls, delay) {
delay += 1;
}
delay
}

solvable!(day_13, day_13_v1, day_13_v2, u32);

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

const SAMPLE: &str = "0: 3\n\
1: 2\n\
4: 4\n\
6: 4";

#[test]
fn works_with_samples_v1() {
assert_eq!(day_13_v1(SAMPLE), 24);
}

#[test]
fn works_with_samples_v2() {
assert_eq!(day_13_v2(SAMPLE), 10);
}
}

0 comments on commit 123bc36

Please sign in to comment.