Skip to content

Commit

Permalink
Year 2017: Day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 30, 2024
1 parent 50cb032 commit d7c4452
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 5 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ 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.16.1]
### Added
- Solved [exercice for 2017, day 16](src/year_2017/16.rs).

## [2017.15.1]
### Added
- Solved [exercice for 2017, day 15](src/year_2017/15.rs).

## [2017.14.1]
### Added
- Solved [exercice for 2017, day 14](src/year_2017/14.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 = "2017.15.1"
version = "2017.16.1"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down
4 changes: 4 additions & 0 deletions NOTES_2017.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ I kinda liked this one.
## Day 15: Dueling Generators

The most interesting part of these exercises is often [all the obscure maths you can leanr about](https://www.reddit.com/r/adventofcode/comments/7jyz5x/2017_day_15_opportunities_for_optimization/drasfzr/?context=3), in that case [Mersenne prime](https://en.wikipedia.org/wiki/Mersenne_prime). But the peculiarities of the number used for the remainder [should have been obvious to people who wrote a lot of C](https://doc.rust-lang.org/std/i32/constant.MAX.html).

## Day 16: Permutation Promenade

Nothing hard, until you see how much ONE BILLION ITERATIONS actually is. Good news though: "All loops are about knowing when to stop". In that case, we can just...look for a repetition of the pattern.
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 15](NOTES_2017.md)
- [2017, up to day 16](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 @@ -13,6 +13,7 @@ use advent_rs::year_2017::day_12;
use advent_rs::year_2017::day_13;
use advent_rs::year_2017::day_14;
use advent_rs::year_2017::day_15;
use advent_rs::year_2017::day_16;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn year_2017_day_01(c: &mut Criterion) {
Expand Down Expand Up @@ -243,6 +244,21 @@ fn year_2017_day_15(c: &mut Criterion) {
g2017_day_15.finish();
}

fn year_2017_day_16(c: &mut Criterion) {
let input_day_16 = include_str!("../inputs/year_2017/day_16_input");
assert_eq!(day_16::day_16_v1(input_day_16), "lgpkniodmjacfbeh");
assert_eq!(day_16::day_16_v2(input_day_16), "hklecbpnjigoafmd");

let mut g2017_day_16 = c.benchmark_group("year_2017::day_16");
g2017_day_16.bench_function("year_2017::day_16_v1", |b| {
b.iter(|| day_16::day_16_v1(black_box(input_day_16)))
});
g2017_day_16.bench_function("year_2017::day_16_v2", |b| {
b.iter(|| day_16::day_16_v2(black_box(input_day_16)))
});
g2017_day_16.finish();
}

criterion_group!(
benches,
year_2017_day_01,
Expand All @@ -259,6 +275,7 @@ criterion_group!(
year_2017_day_12,
year_2017_day_13,
year_2017_day_14,
year_2017_day_15
year_2017_day_15,
year_2017_day_16
);
criterion_main!(benches);
1 change: 1 addition & 0 deletions inputs/year_2017/day_16_input

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/year_2017.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod day_12;
pub mod day_13;
pub mod day_14;
pub mod day_15;
pub mod day_16;

pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
if part > 2 {
Expand All @@ -41,6 +42,7 @@ pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
13 => Some(day_13::day_13(part, input).to_string()),
14 => Some(day_14::day_14(part, input).to_string()),
15 => Some(day_15::day_15(part, input).to_string()),
16 => Some(day_16::day_16(part, input).to_string()),
_ => None,
}
}
Expand Down Expand Up @@ -153,4 +155,11 @@ mod tests {
assert_eq!(day_15::day_15_v1(input), 567);
assert_eq!(day_15::day_15_v2(input), 323);
}

#[test]
fn day_16() {
let input = include_str!("../inputs/year_2017/day_16_input");
assert_eq!(day_16::day_16_v1(input), "lgpkniodmjacfbeh");
assert_eq!(day_16::day_16_v2(input), "hklecbpnjigoafmd");
}
}
3 changes: 1 addition & 2 deletions src/year_2017/day_15.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ impl Generator {
}

impl Iterator for Generator {
// We can refer to this type using Self::Item
type Item = u64;

fn next(&mut self) -> Option<Self::Item> {
loop {
let prod = self.value * self.factor;
let g = (prod & 0x7fff_ffff) + (prod >> 31);
self.value = if g >> 31 == 0 { g } else { g - 0x7fff_ffff };
if (self.value & self.multiples - 1) == 0 {
if self.value & (self.multiples - 1) == 0 {
return Some(self.value);
}
}
Expand Down
116 changes: 116 additions & 0 deletions src/year_2017/day_16.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::collections::HashMap;

enum DanceMove {
Spin(usize),
Exchange(usize, usize),
Partner(char, char),
}

struct DanceFloor {
input: Vec<char>,
instructions: Vec<DanceMove>,
}

impl DanceFloor {
fn dance(&mut self) {
self
.instructions
.iter()
.for_each(|instruction| match instruction {
DanceMove::Spin(rotate) => self.input.rotate_right(*rotate),
DanceMove::Exchange(lhs, rhs) => self.input.swap(*lhs, *rhs),
DanceMove::Partner(lhs, rhs) => {
let lhs_id = self.input.iter().position(|c| c == lhs).unwrap();
let rhs_id = self.input.iter().position(|c| c == rhs).unwrap();
self.input.swap(lhs_id, rhs_id)
}
})
}

pub fn new(input: &str, instructions: &str) -> Self {
let input: Vec<char> = input.chars().collect();
let instructions = instructions
.split(',')
.map(|instruction| match &instruction[..1] {
"s" => DanceMove::Spin(instruction[1..].parse::<usize>().unwrap()),
"x" => {
let indexes: Vec<usize> = instruction[1..]
.split('/')
.map(|number| number.parse::<usize>().unwrap())
.collect();
assert_eq!(indexes.len(), 2);
DanceMove::Exchange(indexes[0], indexes[1])
}
"p" => {
let indexes: Vec<char> = instruction[1..]
.split('/')
.map(|chr| chr.chars().next().unwrap())
.collect();
assert_eq!(indexes.len(), 2);
DanceMove::Partner(indexes[0], indexes[1])
}
_ => panic!("Invalid instruction: _{}_", instruction),
})
.collect();
DanceFloor {
input,
instructions,
}
}
}

impl ToString for DanceFloor {
fn to_string(&self) -> String {
self.input.iter().collect::<String>()
}
}

pub fn day_16_v1(input: impl Into<String>) -> String {
let input = input.into();
let input = input.lines().next().unwrap();
let mut dancefloor = DanceFloor::new("abcdefghijklmnop", input);
dancefloor.dance();

dancefloor.to_string()
}

pub fn day_16_v2(input: impl Into<String>) -> String {
let input = input.into();
let input = input.lines().next().unwrap();
let mut dancefloor = DanceFloor::new("abcdefghijklmnop", input);
let mut positions: HashMap<String, i64> = HashMap::new();
let mut idx = 0i64;
while positions.insert(dancefloor.to_string(), idx).is_none() {
dancefloor.dance();
idx += 1;
}
let pos = 1_000_000_000i64 % positions.len() as i64;
positions
.iter()
.find(|(_, value)| **value == pos)
.unwrap()
.0
.clone()
}
solvable!(day_16, day_16_v1, day_16_v2, String);

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

const SAMPLE: &str = "s1,x3/4,pe/b";

#[test]
fn works_with_samples_v1() {
let mut dancefloor = DanceFloor::new("abcde", SAMPLE);
dancefloor.dance();
assert_eq!(dancefloor.to_string(), "baedc");
}

#[test]
fn works_with_samples_v2() {
let mut dancefloor = DanceFloor::new("abcde", SAMPLE);
(0..2).for_each(|_| dancefloor.dance());
assert_eq!(dancefloor.to_string(), "ceadb");
}
}

0 comments on commit d7c4452

Please sign in to comment.