-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathday14.js
117 lines (106 loc) · 3 KB
/
day14.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'use strict';
const fs = require('fs');
const cl = console.log;
fs.readFile('day14.txt', 'utf-8', (err, input) => {
if (err) throw err;
let lines = input.trim().split(/\r?\n/);
let template = lines[0];
let insertions = new Map(lines.splice(2).map(ln => ln.split(' -> ')));
cl(extendedPolymerization(template, insertions, 10));
cl(extendedPolymerization(template, insertions, 40));
});
function extendedPolymerization(template, insertions, steps) {
return twoStageExtend(template, insertions, steps).lowHigh();
}
function twoStageExtend(template, insertions, steps) {
if (steps % 2 !== 0) throw "Even Stevens";
let halfSteps = steps / 2;
let demiStats = new Map();
for (let pair of insertions.keys()) {
demiStats.set(pair, getDemiStats(stringToPolymer(pair), insertions, halfSteps));
}
let demiPolymer = stringToPolymer(template);
for (let i = 0; i < halfSteps; i++) {
demiPolymer = extendPolymer(demiPolymer, insertions);
}
let stats = newStats();
for (let [l, r] of pairwise(demiPolymer)) {
stats.combine(demiStats.get(l + r));
}
stats.inc(template[0]);
return stats;
}
function getDemiStats(polymer, insertions, steps) {
let stats = newStats();
for (let i = 0; i < steps; i++) {
polymer = extendPolymer(polymer, insertions);
}
let skippedFirst = false;
for (let el of polymer) {
if (skippedFirst) {
stats.inc(el);
}
else {
skippedFirst = true;
}
}
return stats;
}
function extendPolymer(polymer, insertions) {
return singles(withInsertions(insertions, pairwise(polymer)));
}
function* withInsertions(insertions, pairs) {
for (let pair of pairs) {
yield insert(insertions, pair);
}
}
function insert(insertions, [l, r]) {
return [l, insertions.get(l + r), r];
}
function* pairwise(polymer) {
let prev = undefined;
for (let el of polymer) {
if (prev !== undefined) {
yield [prev, el];
}
prev = el;
}
}
function* singles(parts) {
let firstCall = true;
for (let part of parts) {
if (firstCall) {
firstCall = false;
yield part[0];
}
yield* part.slice(1);
}
}
function newStats(sourceMap) {
const stats = new Map(sourceMap);
stats.inc = function (el) {
let current = this.get(el);
this.set(el, current ? current + 1 : 1);
}
stats.combine = function (b) {
for (let el of b.keys()) {
let aVal = this.get(el);
let bVal = b.get(el);
this.set(el, aVal ? aVal + bVal : bVal);
}
}
stats.lowHigh = function () {
let low = Infinity, high = -Infinity;
for (let value of this.values()) {
low = value < low ? value : low;
high = value > high ? value : high;
}
return high - low;
}
return stats;
}
function* stringToPolymer(template) {
for (let el of template) {
yield el;
}
}