DEV Community

Cover image for Dueling Generators
Robert Mion
Robert Mion

Posted on

Dueling Generators

Advent of Code 2017 Day 15

Part 1

  1. 40 million?! Wait, is that a lot?
  2. Animating an algorithm
  3. Writing my algorithm

40 million?! Wait, is that a lot?

  • Many prior Part 2's ask for some result after millions or billions of iterations
  • The trick there is either to find a pattern - since performing that many iterations would take forever - or optimize an algorithm's performance so it can, indeed, perform that many iterations within milliseconds
  • This puzzle presents a performance test in Part 1! Or does it?
  • 40 million seems like a lot
  • But let's say I just wanted to perform some simple operation 40 million times
For i from 0 to 40 million
  If i is divisible by 1 million
    Print i
Enter fullscreen mode Exit fullscreen mode

Surprisingly, this loop finishes in a web browser in milliseconds!

That was one operation, though:

1 * 40M = 40M
Enter fullscreen mode Exit fullscreen mode

I will likely have to perform several operations to generate the correct answer for Part 1

5  * 40M = 200M
10 * 40M = 400M
20 * 40M = 800M
Enter fullscreen mode Exit fullscreen mode

Yikes! The performance implication of a few operations seems drastic.

Animating an algorithm

The instructions outline most of this, but it helped me to visualize it as a GIF:
The operations in each iteration

Writing my algorithm

  • This felt very easy to write
  • It is also extremely slow: taking about two minutes to finish
  • But, hey...it works!
let [A,B] = [...stream.matchAll(/\d+/g)].map(el => +el[0])
let pairs = 0
for (let i = 0; i < 40000000; i++) {
  A = (A * 16807) % 2147483647
  B = (B * 48271) % 2147483647
  pairs += (A).toString(2).padStart(32,0).slice(-16) 
        == (B).toString(2).padStart(32,0).slice(-16) 
         ? 1 : 0
}
return pairs
Enter fullscreen mode Exit fullscreen mode
  • I extract the two integers from the input as variables A and B
  • I initialize pairs to 0
  • I run a loop 40M times
  • Each time, I update A and B
  • And increment pairs by 1 if the last 16 digits of each 0-padded binary string representation of the numbers match
  • Otherwise, I increment pairs by 0, leaving it unchanged

It generates the correct answers for the example input and my puzzle input...eventually!

I do wonder how I could achieve near-instant runtime, though.

Part 2

  1. Enter: queues
  2. My working algorithm

Enter: queues

The way I understand it:

Track the number of matching pairs, starting at 0
Track the number of passing values that each generator has given to the judge
While either generator has yet to pass its 5 millionth value to the judge
  Continue generating and checking values for pass/fail
    If any pass, add them to the appropriate one of two queues being tracked by the judge
Exhaust the judge's queue of accrued values
    Check the last 16 bits for an exact match
      If a match, increment the number of matching pairs by 1
Enter fullscreen mode Exit fullscreen mode

My working algorithm

  • I create and pre-fill two typed arrays, specifically UInt32Array(), with 5 million 0s
  • I track the current location to fill in each one, starting at 0
  • I track the number of matching pairs, starting at 0
Do as long as the last number in either array is not 0 (meaning it has been filled with a value that meets the criteria)
  Generate the next number for each generator
  If the array is not already full, and the number meets that generator's criteria
    Set the value at the current location as that number
    Increment the value to refer to the next location

For i from 0 up to but not including 5000000
  Increment pairs by 1 if the converted-to-binary-and-sliced numbers at location i in each array are a match
Enter fullscreen mode Exit fullscreen mode

Similar to Part 1, my algorithm takes a few minutes to run.

If you'd like, you can watch it run, too:
My algorithm processing in real-time

Regardless of its slowness, it generated the correct answer!

I did it!!

  • I solved both parts!
  • By writing two very slow, but working algorithms!
  • I used a typed array for the...second?...time!
  • I got more practice learning the subtle difference between || and && operators in JavaScript
  • I made a short GIF that visually depicts the equation described in the instructions

Wow. I'm going in to Day 14 with 18 stars!

This feels incredible!

I'll admit, I'm still prepared for a few puzzles that I'm unable to solve due to their theme (e.g. pathfinding, tree data structures, performance stress tests).

Top comments (0)