Skip to content

Commit 4558bed

Browse files
committed
Added 2017 day 13
1 parent fc0e1a2 commit 4558bed

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed

2017/13/code.mjs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { delay, Console, PixelMap, leastCommonMultiple } from "../../utility.mjs";
2+
3+
const packetColorIndex = 1;
4+
const packetColor = "#ffffff";
5+
const scannerColorIndex = 2;
6+
const scannerColor = "#999999";
7+
const caughtColorIndex = 3;
8+
const caughtColor = "#ff0000";
9+
10+
export default class {
11+
/**
12+
* @param {Console} solConsole Solution console.
13+
* @param {HTMLElement} visContainer Visualization container.
14+
*/
15+
constructor(solConsole, visContainer) {
16+
this.isSolving = false;
17+
this.isStopping = false;
18+
this.solConsole = typeof solConsole !== "undefined" ? solConsole : new Console();
19+
this.visContainer = visContainer;
20+
}
21+
22+
/**
23+
* Parses the puzzle input.
24+
* @param {string} input Puzzle input.
25+
* @returns {number[]} Scanner ranges.
26+
*/
27+
parse(input) {
28+
let consoleLine = this.solConsole.addLine("Parsing...");
29+
30+
let scannerRanges = [];
31+
input.trim().split(/\r?\n/).forEach((line, index) => {
32+
let match = line.match(/^(\d+): (\d+)$/);
33+
if (match == null)
34+
throw new Error(`Invalid data in line ${index + 1}`);
35+
let layerIndex = parseInt(match[1]);
36+
let range = parseInt(match[2]);
37+
for (let i = scannerRanges.length; i <= layerIndex; i++)
38+
scannerRanges.push(0);
39+
scannerRanges[layerIndex] = range;
40+
});
41+
42+
consoleLine.innerHTML += " done.";
43+
return scannerRanges;
44+
}
45+
46+
47+
/**
48+
* Finds the severity of trip through the firewall.
49+
* @param {number} part Puzzle part.
50+
* @param {string} input Puzzle input.
51+
* @param {boolean} visualization Enable visualization.
52+
* @returns {number} Severity of trip through the firewall.
53+
*/
54+
async solve(part, input, visualization) {
55+
try {
56+
this.isSolving = true;
57+
58+
let scannerRanges = this.parse(input);
59+
60+
let solConsoleLine;
61+
let pixelMap = new PixelMap(scannerRanges.length, Math.max(...scannerRanges, 1));
62+
if (visualization) {
63+
solConsoleLine = this.solConsole.addLine();
64+
65+
this.visContainer.append(pixelMap.container);
66+
pixelMap.palette[packetColorIndex] = packetColor;
67+
pixelMap.palette[scannerColorIndex] = scannerColor;
68+
pixelMap.palette[caughtColorIndex] = caughtColor;
69+
}
70+
71+
let maxPacketDelay = scannerRanges.reduce((acc, e) => leastCommonMultiple(acc, Math.max(1, (e - 1) * 2)), 1);
72+
73+
for (let packetDelay = 0; packetDelay < maxPacketDelay; packetDelay++) {
74+
let caught = false;
75+
let severity = 0;
76+
for (let i = 0; i < scannerRanges.length; i++) {
77+
if (scannerRanges[i] > 0 && (scannerRanges[i] == 1 || (packetDelay + i) % ((scannerRanges[i] - 1) * 2) == 0)) {
78+
caught = true;
79+
severity += i * scannerRanges[i];
80+
}
81+
}
82+
83+
if (part == 1 || (part == 2 && !caught)) {
84+
if (visualization) {
85+
if (part == 2)
86+
solConsoleLine.innerHTML = `Delay: ${packetDelay}.`;
87+
88+
severity = 0;
89+
for (let i = 0; i < scannerRanges.length; i++) {
90+
if (this.isStopping)
91+
return;
92+
93+
for (let x = 0; x < pixelMap.width; x++) {
94+
let scannerY = -1;
95+
if (scannerRanges[x] == 1)
96+
scannerY = 0;
97+
else if (scannerRanges[x] > 1) {
98+
scannerY = (packetDelay + i) % ((scannerRanges[x] - 1) * 2);
99+
if (scannerY >= scannerRanges[x])
100+
scannerY = (scannerRanges[x] - 2) - (scannerY - scannerRanges[x]);
101+
}
102+
103+
for (let y = 0; y < pixelMap.height; y++) {
104+
pixelMap.drawPixel(x, y, scannerY == y ? scannerColorIndex : 0);
105+
}
106+
}
107+
108+
pixelMap.drawPixel(i, 0, pixelMap.image[0][i] == 0 ? packetColorIndex : caughtColorIndex);
109+
if (pixelMap.image[0][i] == caughtColorIndex)
110+
severity += i * scannerRanges[i];
111+
if (part == 1)
112+
solConsoleLine.innerHTML = `Severity: ${severity}.`;
113+
114+
await delay(100);
115+
}
116+
}
117+
118+
return part == 1 ? severity : packetDelay;
119+
}
120+
}
121+
122+
throw new Error("Solution not found");
123+
}
124+
125+
finally {
126+
this.isSolving = false;
127+
}
128+
}
129+
130+
/**
131+
* Stops solving the puzzle.
132+
*/
133+
async stopSolving() {
134+
this.isStopping = true;
135+
while (this.isSolving)
136+
await(delay(10));
137+
this.isStopping = false;
138+
}
139+
}

2017/13/testInput.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0: 3
2+
1: 2
3+
4: 4
4+
6: 4

tree.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,10 @@ export const years = [
446446
{
447447
name: "Day 12: Digital Plumber", path: "./2017/12", taskUrl: "https://adventofcode.com/2017/day/12",
448448
answers: {part1: 6, part2: 2}
449+
},
450+
{
451+
name: "Day 13: Packet Scanners", path: "./2017/13", taskUrl: "https://adventofcode.com/2017/day/13",
452+
answers: {part1: 24, part2: 10}
449453
}
450454
]
451455
},

0 commit comments

Comments
 (0)