JavaScript solutions for Advent of Code 2018 using the latest ECMAScript features.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
input
util
.gitignore
01.mjs
02.mjs
03.mjs
04.mjs
05.mjs
06.mjs
07.mjs
08.mjs
09.mjs
10.mjs
11.mjs
12.mjs
13.mjs
README.md

README.md

Advent of ES

JavaScript solutions for Advent of Code 2018 using the latest ECMAScript features, specifically generators and iterators.

Run

Requires node 11+. Input via stdin, e.g.

cat input/01.txt | ./01.mjs

.mjs files are exectutable to avoid having to type node --experimental-modules over and over again.

Not your granpa's JS

With generators, complex computations can be represented using functional building blocks. For example, finding the first duplicate in an (infinite) series of additions can be expressed as:

console.log(pipe(
    cycle(input),
    scan((a, b) => a + b, 0),
    scan((seen, freq) => 
        seen.has(freq)
            ? { reduced: freq }
            : seen.add(freq),
        new Set(),
    ),
    find(({ reduced }) => reduced),
).reduced);

Thanks to the pull-based nature of iterators, we can start with an infinite series (cycle(input)) but stop producing new items as soon as we find a result.

In other words, the above solution does not run any more iterations as a more verbose implementation using an infinite loop.

const seen = new Set();
let freq = 0;
let i = 0;
while (true) {
    freq += input[i];
    if (seen.has(freq)) {
        console.log(freq);
        break;
    }
    seen.add(freq);
    i = (i + 1) % input.length;
}

Why is the first solution "better"? It's really a matter of taste, but personally I prefer the fact that each idea is expressed separately. I.e. the cycling of the input is one line instead of explicitly incrementing and wrapping and index, as is the lookup in the set, etc...

Obviously the first implementation requires a variety of helper functions such as pipe, scan, find, etc. However, as a look at util.mjs will show, they are suprisingly compact and easy to implement using generator functions.

Further Reading