-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday15.js
161 lines (138 loc) · 4.44 KB
/
day15.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const fs = require('fs');
const day15a = () => {
// const filename = './data/day15test.txt'; // 26
// const targetRow = 10;
const filename = './data/day15.txt'; // 5461729
const targetRow = 2000000;
const arr = buildGridLite(filename);
// get all the sensors and beacons on the target row.
const sbSet = new Set();
for (let item of arr) {
const sPt = item['sensor'];
const bPt = item['beacon'];
if (sPt[0] === targetRow) {
sbSet.add(key(sPt[0], sPt[1]));
}
if (bPt[0] === targetRow) {
sbSet.add(key(bPt[0], bPt[1]));
}
}
// all deadzones.
const deadZones = [];
for (const item of arr) {
const [sensorRow, sensorCol] = item['sensor'];
const manhattanDist = item['manhattanDist'];
const mD = minDistance(item['sensor'], targetRow);
if (mD <= manhattanDist) {
exploreDeadZones([sensorRow, sensorCol], manhattanDist, targetRow, deadZones);
} else {
// console.log('skipped this because outside range');
}
}
// deadzones - sensors/beacons on the target row.
const deadzoneCount = overlap(deadZones);
console.log('day15a = ', deadzoneCount - sbSet.size);
}
const exploreDeadZones = (sensorPt, manhattanDist, targetRow, deadZones) => {
const [r, c] = sensorPt;
const mDist = minDistance(sensorPt, targetRow);
const delta = manhattanDist - mDist;
const range = [c - delta, c + delta];
deadZones.push(range);
}
// find overlapping values in array.
const overlap = (v) => {
// sort the input by minimums.
v.sort((a, b) => a[0] - b[0]);
// console.log(v);
let [min, max] = v[0];
for (let i = 1; i < v.length; i++) {
// console.log(`compare. ${v[i][0]} >= ${min} && ${v[i][0]} <= ${max}`);
if (v[i][0] >= min && v[i][0] <= max) {
// console.log(v[i]);
min = Math.min(min, v[i][0]);
max = Math.max(max, v[i][1]);
} else {
console.log('start new range. implementation incomplete but luckily not needed');
}
}
// console.log(min, max);
return max - min + 1; // inclusive of max
}
const minDistance = (pt, targetRow) => {
return Math.abs(pt[0] - targetRow);
}
const key = (r, c) => {
return `${r},${c}`;
}
const day15b = () => {
// const filename = './data/day15test.txt'; // x =14, y = 11 ==> 56000011
// const maxRange = 20;
const filename = './data/day15.txt'; // 10621647166538
const maxRange = 4000000;
const arr = buildGridLite(filename);
for (let row = 0; row < maxRange; row++) {
let segments = [];
for (let item of arr) {
const sensorPt = item['sensor'];
const manhattanDist = item['manhattanDist'];
let distToRow = minDistance(sensorPt, row);
let remainingDist = manhattanDist - distToRow;
if (remainingDist >= 0) {
let minC = sensorPt[1] - remainingDist;
let maxC = sensorPt[1] + remainingDist;
segments.push([minC, maxC]);
}
}
let missingCol = findMissingValue(segments, maxRange);
if (missingCol >= 0)
{
const answer = 4000000 * missingCol + row;
console.log(`Mystery beacon located at ${row},${missingCol}`);
console.log('day15b = ', answer);
return;
}
// console.log(row, segments);
}
}
const findMissingValue = (v, maxRange) => {
v.sort((a, b) => a[0] - b[0]);
v.map(segment => {
if (segment[0] < 0) segment[0] = 0;
if (segment[1] > maxRange) segment[1] = maxRange;
});
let [min, max] = v[0];
for (let i = 1; i < v.length; i++) {
// console.log(`compare. ${v[i][0]} >= ${min} && ${v[i][0]} <= ${max}`);
if (v[i][0] >= min && v[i][0] <= max) {
// console.log(v[i]);
min = Math.min(min, v[i][0]);
max = Math.max(max, v[i][1]);
} else {
console.log(`there is a break between ${v[i-1][1]} - ${v[i][0]}`);
return v[i-1][1] + 1;
}
}
return -1; // all segments are overlapping.
}
const calculateManhattanDist = (pt1, pt2) => {
const dR = Math.abs(pt2[0] - pt1[0]);
const dC = Math.abs(pt2[1] - pt1[1]);
return dR + dC;
}
const buildGridLite = (filename) => {
const lines = fs.readFileSync(filename,
{ encoding: 'utf8', flag: 'r' }).split('\n');
const grid = [];
const arr = [];
lines.forEach(line => {
const matches = line.match(/-?\d+/g);
const sr = +matches[1];
const sc = +matches[0];
const br = +matches[3];
const bc = +matches[2];
arr.push({ sensor: [sr, sc], beacon: [br, bc], manhattanDist: calculateManhattanDist([sr, sc], [br, bc]) });
});
return arr;
}
module.exports = { day15a, day15b }