-
Notifications
You must be signed in to change notification settings - Fork 0
/
day3.js
120 lines (105 loc) · 3.84 KB
/
day3.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
'use strict';
// get Manhattan distance
function aocd3p1(num) {
var coords = getPositionCoordinates(num);
return Math.abs(coords[0]) + Math.abs(coords[1]);
// find the largest complete ring
function getLargestCompleteRing(positionNumber) {
return Math.ceil(Math.floor(Math.sqrt(positionNumber)) / 2);
}
// a 5x5 grid should return 4 because the outer ring is 16 squares
function getSideLength(ring) {
if (ring > 1) {
return (ring * 2) - 2;
}
return 1;
}
function getRemainingPositions(positionNumber, completeRing) {
return positionNumber - (((completeRing * 2) - 1) ** 2);
}
function getPositionCoordinates(positionNumber) {
if (positionNumber === 1) {
return [0, 0];
}
var completeRing = getLargestCompleteRing(positionNumber);
var remainingRingPositions = getRemainingPositions(positionNumber, completeRing);
var currentRing = remainingRingPositions === 0 ? completeRing : completeRing + 1;
var positionsPerSide = getSideLength(currentRing);
var completeSides = Math.floor(remainingRingPositions / positionsPerSide);
var activeSidePositions = remainingRingPositions % positionsPerSide;
var maxDistanceFromCenter = positionsPerSide / 2;
switch (completeSides) {
case 0:
return [maxDistanceFromCenter, -maxDistanceFromCenter + activeSidePositions];
case 1:
return [maxDistanceFromCenter - activeSidePositions, maxDistanceFromCenter];
case 2:
return [-maxDistanceFromCenter, maxDistanceFromCenter - activeSidePositions];
case 3:
return [-maxDistanceFromCenter + activeSidePositions, -maxDistanceFromCenter];
case 4:
return [maxDistanceFromCenter, -maxDistanceFromCenter];
}
}
}
// a fundamentally different approach is needed :(
function aocd3p2(input) {
var max = 0;
var initialCoordinates = [0, 0];
var previousCoordinates = initialCoordinates.toString();
var positions = {};
positions[initialCoordinates] = {
coords: initialCoordinates,
index: 1,
value: 1
};
while (positions[previousCoordinates].value <= input) {
let current = Object.assign({}, positions[previousCoordinates]);
current.index++;
if (current.coords[0] === max && current.coords[1] === -max) {
current.coords[0]++;
max++;
}
// go up
else if (current.coords[0] === max && current.coords[1] < max) {
current.coords[1]++;
}
// go left
else if (current.coords[0] > -max && current.coords[1] === max) {
current.coords[0]--;
}
// go down
else if (current.coords[0] === -max && current.coords[1] > -max) {
current.coords[1]--;
}
// go right
else if (current.coords[0] < max && current.coords[1] === -max) {
current.coords[0]++;
}
current.value = addAdjacentValues(current.coords[0], current.coords[1]);
previousCoordinates = current.coords.toString();
positions[previousCoordinates] = current;
}
return positions[previousCoordinates].value;
function getValue(coords) {
if (positions[coords] && positions[coords].value) {
return positions[coords].value;
}
return 0;
}
function addAdjacentValues(x, y) {
var adjacentPoints = [
[x + 1, y],
[x + 1, y + 1],
[x, y + 1],
[x - 1, y + 1],
[x - 1, y],
[x - 1, y - 1],
[x, y - 1],
[x + 1, y -1]
];
return adjacentPoints.reduce(function reducer(sum, coords) {
return sum + getValue(coords);
}, 0);
}
}