Skip to content

Commit 8d620f8

Browse files
committed
Added 2017 day 03
1 parent 0e5f394 commit 8d620f8

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

2017/03/code.mjs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { delay, Console, Vector2D } from "../../utility.mjs";
2+
3+
export default class {
4+
/**
5+
* @param {Console} solConsole Solution console.
6+
* @param {HTMLElement} visContainer Visualization container.
7+
*/
8+
constructor(solConsole, visContainer) {
9+
this.isSolving = false;
10+
this.isStopping = false;
11+
this.solConsole = typeof solConsole !== "undefined" ? solConsole : new Console();
12+
this.visContainer = visContainer;
13+
}
14+
15+
/**
16+
* Parses the puzzle input.
17+
* @param {string} input Puzzle input.
18+
* @returns {number} Square number.
19+
*/
20+
parse(input) {
21+
let consoleLine = this.solConsole.addLine("Parsing...");
22+
23+
input = input.trim();
24+
if (!/^\d+$/.test(input))
25+
throw new Error("Invalid input data")
26+
27+
let squareNumber = parseInt(input);
28+
29+
consoleLine.innerHTML += " done.";
30+
return squareNumber;
31+
}
32+
33+
34+
/**
35+
* Finds the Manhattan distance from the specified square to the center of the spiral (part 1) or the first square value that is larger than the specified value (part 2).
36+
* @param {number} part Puzzle part.
37+
* @param {string} input Puzzle input.
38+
* @param {boolean} visualization Enable visualization.
39+
* @returns {number} Manhattan distance from the specified square to the center of the spiral (part 1) or the first square value that is larger than the specified value (part 2).
40+
*/
41+
async solve(part, input, visualization) {
42+
try {
43+
this.isSolving = true;
44+
45+
let puzzleInput = this.parse(input);
46+
47+
let visConsole = new Console();
48+
if (visualization)
49+
this.visContainer.append(visConsole.container);
50+
51+
if (part == 1) {
52+
let squareCoordinates = this.squareNumberToCoordinates(puzzleInput);
53+
if (visualization)
54+
visConsole.addLine(`Square ${puzzleInput} coordinates relative to the spiral center: (${squareCoordinates.x}, ${squareCoordinates.y}).`);
55+
return Math.abs(squareCoordinates.x) + Math.abs(squareCoordinates.y);
56+
}
57+
else {
58+
let value = 0;
59+
let valueMap = new Map();
60+
for (let i = 1; value <= puzzleInput; i++) {
61+
let coordinates = this.squareNumberToCoordinates(i);
62+
63+
if (i == 1)
64+
value = 1;
65+
else {
66+
let neighborsCoordinates = [new Vector2D(coordinates.x - 1, coordinates.y - 1), new Vector2D(coordinates.x, coordinates.y - 1), new Vector2D(coordinates.x + 1, coordinates.y - 1),
67+
new Vector2D(coordinates.x - 1, coordinates.y), new Vector2D(coordinates.x, coordinates.y), new Vector2D(coordinates.x + 1, coordinates.y),
68+
new Vector2D(coordinates.x - 1, coordinates.y + 1), new Vector2D(coordinates.x, coordinates.y + 1), new Vector2D(coordinates.x + 1, coordinates.y + 1)];
69+
value = 0;
70+
for (let neighborCoordinates of neighborsCoordinates) {
71+
let neighborValue = valueMap.get(`${neighborCoordinates.x}|${neighborCoordinates.y}`);
72+
if (neighborValue != undefined)
73+
value += neighborValue;
74+
}
75+
}
76+
77+
valueMap.set(`${coordinates.x}|${coordinates.y}`, value);
78+
79+
if (visualization) {
80+
visConsole.addLine(`Square ${i}: <span${value > puzzleInput ? " class='highlighted'" : ""}>${value}</span>${value > puzzleInput ? " > " + puzzleInput : ""}.`)
81+
visConsole.container.scrollTop = visConsole.lines[visConsole.lines.length - 1].offsetTop - visConsole.container.offsetHeight / 2;
82+
}
83+
}
84+
return value;
85+
}
86+
}
87+
88+
finally {
89+
this.isSolving = false;
90+
}
91+
}
92+
93+
/**
94+
* Calculates the coordinates of the specified square relative to the spiral center.
95+
* @param {number} squareNumber Square number.
96+
* @returns {Vector2D} Square coordinates relative to the spiral center.
97+
*/
98+
squareNumberToCoordinates(squareNumber) {
99+
if (squareNumber == 1)
100+
return new Vector2D(0, 0);
101+
// Numbers of squares in full turns are: 1, 8, 16, 24, 32...
102+
// Find the turn index from the square number using the arithmetic progression sum formula
103+
let turnIndex = Math.floor((1 + Math.sqrt(1 + 8 * (squareNumber - 2) / 8)) / 2);
104+
let squareIndexInTurn = (squareNumber - 2 - turnIndex * (turnIndex - 1) * 8 / 2);
105+
let sideIndex = Math.floor(squareIndexInTurn / (turnIndex * 2));
106+
let squareIndexOnTheSide = squareIndexInTurn % (turnIndex * 2);
107+
if (sideIndex == 0)
108+
return new Vector2D(turnIndex, turnIndex - 1 - squareIndexOnTheSide);
109+
else if (sideIndex == 1)
110+
return new Vector2D(turnIndex - 1 - squareIndexOnTheSide, -turnIndex);
111+
else if (sideIndex == 2)
112+
return new Vector2D(-turnIndex, squareIndexOnTheSide - (turnIndex - 1));
113+
else
114+
return new Vector2D(squareIndexOnTheSide - (turnIndex - 1), turnIndex);
115+
}
116+
117+
/**
118+
* Stops solving the puzzle.
119+
*/
120+
async stopSolving() {
121+
this.isStopping = true;
122+
while (this.isSolving)
123+
await(delay(10));
124+
this.isStopping = false;
125+
}
126+
}

2017/03/testInput.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1024

tree.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ export const years = [
406406
{
407407
name: "Day 2: Corruption Checksum", path: "./2017/02", taskUrl: "https://adventofcode.com/2017/day/2",
408408
answers: {part1: 18, part2: 9}
409+
},
410+
{
411+
name: "Day 3: Spiral Memory", path: "./2017/03", taskUrl: "https://adventofcode.com/2017/day/3",
412+
answers: {part1: 31, part2: 1968}
409413
}
410414
]
411415
},

0 commit comments

Comments
 (0)