Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dd2bf49

Browse files
committedJun 2, 2024·
Year 2017 Day 18
1 parent 7b78f45 commit dd2bf49

File tree

7 files changed

+119
-0
lines changed

7 files changed

+119
-0
lines changed
 

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
253253
| 15 | [Dueling Generators](https://adventofcode.com/2017/day/15) | [Source](src/year2017/day15.rs) | 425000 |
254254
| 16 | [Permutation Promenade](https://adventofcode.com/2017/day/16) | [Source](src/year2017/day16.rs) | 66 |
255255
| 17 | [Spinlock](https://adventofcode.com/2017/day/17) | [Source](src/year2017/day17.rs) | 84 |
256+
| 18 | [Duet](https://adventofcode.com/2017/day/18) | [Source](src/year2017/day18.rs) | 7 |
256257

257258
## 2016
258259

‎benches/benchmark.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ mod year2017 {
118118
benchmark!(year2017, day15);
119119
benchmark!(year2017, day16);
120120
benchmark!(year2017, day17);
121+
benchmark!(year2017, day18);
121122
}
122123

123124
mod year2019 {

‎src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub mod year2017 {
100100
pub mod day15;
101101
pub mod day16;
102102
pub mod day17;
103+
pub mod day18;
103104
}
104105

105106
/// # Rescue Santa from deep space with a solar system adventure.

‎src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ fn year2017() -> Vec<Solution> {
165165
solution!(year2017, day15),
166166
solution!(year2017, day16),
167167
solution!(year2017, day17),
168+
solution!(year2017, day18),
168169
]
169170
}
170171

‎src/year2017/day18.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! # Duet
2+
//!
3+
//! Reverse engineering the code shows that the program is broken into 2 sections.
4+
//! Each input differs only in the number specified on line 10.
5+
//!
6+
//! The first section is only executed by program 0 and generates a pseudorandom sequence of
7+
//! 127 numbers between 0 and 9999. The programs then take turns implementing the innner loop of
8+
//! the [imfamous bubble sort](https://en.wikipedia.org/wiki/Bubble_sort) in descending order.
9+
//!
10+
//! The partially sorted sequence is passed back and forth between each program until in final
11+
//! sorted order. Assembly code annotated with Rust pseduocode:
12+
//!
13+
//! ```none
14+
//! set i 31
15+
//! set a 1
16+
//! mul p 17
17+
//! jgz p p if p == 0 {
18+
//! mul a 2 let a = 2 ^ 31 - 1 = 0x7fffffff;
19+
//! add i -1
20+
//! jgz i -2
21+
//! add a -1
22+
//! set i 127
23+
//! set p SEED let mut p = SEED;
24+
//! mul p 8505 for _ in 0..127 {
25+
//! mod p a p = (p * 8505) % a;
26+
//! mul p 129749
27+
//! add p 12345
28+
//! mod p a p = (p * 129749 + 12345) % a;
29+
//! set b p
30+
//! mod b 10000
31+
//! snd b send(p % 10000)
32+
//! add i -1
33+
//! jgz i -9 }
34+
//! jgz a 3 }
35+
//! rcv b // These two lines deadlock the program
36+
//! jgz b -1 // once the list is sorted.
37+
//! set f 0 while swapped { // f is 0 when list is sorted
38+
//! set i 126 a = receive();
39+
//! rcv a for _ in 0..126 {
40+
//! rcv b b = receive();
41+
//! set p a
42+
//! mul p -1
43+
//! add p b
44+
//! jgz p 4 if b <= a {
45+
//! snd a send(a);
46+
//! set a b a = b;
47+
//! jgz 1 3 } else {
48+
//! snd b send(b);
49+
//! set f 1 swapped = true;
50+
//! add i -1 }
51+
//! jgz i -11 }
52+
//! snd a
53+
//! jgz f -16 }
54+
//! jgz a -19 // Jump to deadlock section.
55+
//! ```
56+
use crate::util::parse::*;
57+
58+
/// Generate a pseudorandom sequence of 127 numbers, based on a
59+
/// starting seed different for each input.
60+
pub fn parse(input: &str) -> Vec<u64> {
61+
// Read the starting seed from the input.
62+
let mut p: u64 = input.lines().nth(9).unwrap().unsigned();
63+
let mut numbers = Vec::with_capacity(127);
64+
65+
// Generate pseudorandom sequence.
66+
for _ in 0..127 {
67+
p = (p * 8505) % 0x7fffffff;
68+
p = (p * 129749 + 12345) % 0x7fffffff;
69+
numbers.push(p % 10000);
70+
}
71+
72+
numbers
73+
}
74+
75+
/// Part one is the last number sent in the sequence.
76+
pub fn part1(input: &[u64]) -> u64 {
77+
input[126]
78+
}
79+
80+
/// Bubble sort the sequence into descending order, counting the number of passes.
81+
/// Starting with program 1 each program alternates sorting the input by sending it to the other
82+
/// program, so the number of passes that program 1 takes is the total divided by two rounding up.
83+
pub fn part2(input: &[u64]) -> usize {
84+
let mut numbers = input.to_vec();
85+
let mut swapped = true;
86+
let mut count = 0;
87+
88+
// Bubble sort in descending order.
89+
while swapped {
90+
swapped = false;
91+
92+
// "Optimized" version skipping the last count elements as these are already sorted.
93+
for i in 1..127 - count {
94+
if numbers[i - 1] < numbers[i] {
95+
numbers.swap(i - 1, i);
96+
swapped = true;
97+
}
98+
}
99+
100+
count += 1;
101+
}
102+
103+
// The sequence countains 127 numbers so the final result is multiplied by that factor.
104+
127 * count.div_ceil(2)
105+
}

‎tests/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ mod year2017 {
102102
mod day15_test;
103103
mod day16_test;
104104
mod day17_test;
105+
mod day18_test;
105106
}
106107

107108
mod year2019 {

‎tests/year2017/day18_test.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[test]
2+
fn part1_test() {
3+
// No example data
4+
}
5+
6+
#[test]
7+
fn part2_test() {
8+
// No example data
9+
}

0 commit comments

Comments
 (0)
Please sign in to comment.