Compare commits
3 Commits
3ad67df338
...
888f40d341
| Author | SHA1 | Date | |
|---|---|---|---|
| 888f40d341 | |||
| 33a8ce77e4 | |||
| ed88c69cea |
128
functions/src/day11.ts
Normal file
128
functions/src/day11.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import Day from "./day";
|
||||||
|
|
||||||
|
class Day11 implements Day {
|
||||||
|
|
||||||
|
part1(input: string[]): number | string {
|
||||||
|
|
||||||
|
const grid = OctopusGrid.parse(input);
|
||||||
|
|
||||||
|
let flashTotal = 0;
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
flashTotal += grid.runStep();
|
||||||
|
}
|
||||||
|
return flashTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
part2(input: string[]): number | string {
|
||||||
|
const grid = OctopusGrid.parse(input);
|
||||||
|
|
||||||
|
let lastFlash = 0;
|
||||||
|
let step = 0;
|
||||||
|
while(lastFlash !== 100) {
|
||||||
|
lastFlash = grid.runStep();
|
||||||
|
step++;
|
||||||
|
}
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class OctopusGrid {
|
||||||
|
grid: number[];
|
||||||
|
maxX: number;
|
||||||
|
maxY: number;
|
||||||
|
|
||||||
|
constructor(grid: number[], width: number) {
|
||||||
|
|
||||||
|
this.grid = grid;
|
||||||
|
this.maxX = width;
|
||||||
|
this.maxY = grid.length / width;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse(input: string[]): OctopusGrid {
|
||||||
|
|
||||||
|
const grid = input.map(l => l.split("").map(s => parseInt(s)))
|
||||||
|
.reduce((a, b) => [...a, ...b])
|
||||||
|
const width = input[0].length;
|
||||||
|
|
||||||
|
return new OctopusGrid(grid, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
runStep(): number {
|
||||||
|
|
||||||
|
// First, the energy level of each octopus increases by 1.
|
||||||
|
this.grid = this.grid.map(o => o + 1);
|
||||||
|
|
||||||
|
// Then, any octopus with an energy level greater than 9 flashes. This increases the energy level of all adjacent
|
||||||
|
// octopuses by 1, including octopuses that are diagonally adjacent. If this causes an octopus to have an energy
|
||||||
|
// level greater than 9, it also flashes. This process continues as long as new octopuses keep having their energy
|
||||||
|
// level increased beyond 9. (An octopus can only flash at most once per step.)
|
||||||
|
const flashGrid = Array(this.grid.length).fill(false);
|
||||||
|
|
||||||
|
for (let y = 0; y < this.maxY; y++) {
|
||||||
|
for (let x = 0; x < this.maxX; x++) {
|
||||||
|
const i = this.index(x, y);
|
||||||
|
const cur = this.grid[i];
|
||||||
|
if (cur > 9 && !flashGrid[i]) {
|
||||||
|
this.flash(x, y, flashGrid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, any octopus that flashed during this step has its energy level set to 0, as it used all of its energy to flash.
|
||||||
|
for (let y = 0; y < this.maxY; y++) {
|
||||||
|
for (let x = 0; x < this.maxX; x++) {
|
||||||
|
const i = this.index(x, y);
|
||||||
|
if (flashGrid[i]) {
|
||||||
|
this.grid[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flashGrid.filter(f => f).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash(x: number, y: number, flashGrid: boolean[]) {
|
||||||
|
|
||||||
|
flashGrid[this.index(x, y)] = true;
|
||||||
|
|
||||||
|
// Charge and if needed flash all neighbors
|
||||||
|
for (let ny = y - 1; ny <= y + 1; ny++) {
|
||||||
|
for (let nx = x - 1; nx <= x + 1 ; nx++) {
|
||||||
|
this.chargeAndFlashIfNeeded(nx, ny, flashGrid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chargeAndFlashIfNeeded(x: number, y: number, flashGrid: boolean[]) {
|
||||||
|
// Short circuit for octopuses outside the grid
|
||||||
|
if (x < 0 || x >= this.maxX || y < 0 || y >= this.maxY) return;
|
||||||
|
|
||||||
|
const i = this.index(x, y);
|
||||||
|
this.grid[i] += 1;
|
||||||
|
if (this.grid[i] > 9 && !flashGrid[i]) {
|
||||||
|
this.flash(x, y, flashGrid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index(x: number, y: number): number {
|
||||||
|
return x + y * this.maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
for (let y = 0; y < this.maxY; y++) {
|
||||||
|
let line = "";
|
||||||
|
for (let x = 0; x < this.maxX; x++) {
|
||||||
|
line += this.grid[this.index(x, y)];
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Day11;
|
||||||
72
functions/src/day12.ts
Normal file
72
functions/src/day12.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import Day from "./day";
|
||||||
|
|
||||||
|
class Day12 implements Day {
|
||||||
|
|
||||||
|
part1(input: string[]): number | string {
|
||||||
|
|
||||||
|
const caves = this.parseInput(input);
|
||||||
|
return this.countPaths("start", caves, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
part2(input: string[]): number | string {
|
||||||
|
|
||||||
|
const caves = this.parseInput(input);
|
||||||
|
return this.countPaths("start", caves, [], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseInput(input: string[]) {
|
||||||
|
const caves = new Map<string, string[]>();
|
||||||
|
for (const line of input) {
|
||||||
|
const splitIndex = line.indexOf("-");
|
||||||
|
const from = line.substr(0, splitIndex);
|
||||||
|
const to = line.substr(splitIndex + 1);
|
||||||
|
|
||||||
|
this.addPath(from, to, caves);
|
||||||
|
this.addPath(to, from, caves);
|
||||||
|
}
|
||||||
|
return caves;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPath(from: string, to: string, caves: Map<string, string[]>): void {
|
||||||
|
const existing = caves.get(from);
|
||||||
|
if (existing) {
|
||||||
|
existing.push(to);
|
||||||
|
} else {
|
||||||
|
caves.set(from, [to]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countPaths(pos: string, caves: Map<string, string[]>, visited: string[], secondSmallVisitAllowed = false): number {
|
||||||
|
|
||||||
|
// If we reached the end, there is exactly one path
|
||||||
|
if (pos === "end") return 1;
|
||||||
|
|
||||||
|
const destinations = caves.get(pos);
|
||||||
|
if (!destinations) {
|
||||||
|
throw Error(`No paths from ${pos}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newVisited = [...visited];
|
||||||
|
if (this.isSmall(pos)) {
|
||||||
|
newVisited.push(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sum = 0;
|
||||||
|
for (const destination of destinations) {
|
||||||
|
if (!this.isSmall(destination) || !visited.includes(destination)) {
|
||||||
|
sum += this.countPaths(destination, caves, newVisited, secondSmallVisitAllowed)
|
||||||
|
} else if (secondSmallVisitAllowed && destination !== "start") {
|
||||||
|
sum += this.countPaths(destination, caves, newVisited, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmall(cave: string): boolean {
|
||||||
|
return cave.toLowerCase() === cave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Day12;
|
||||||
100
functions/src/day13.ts
Normal file
100
functions/src/day13.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import Day from "./day";
|
||||||
|
import Vector2 from "./vector2";
|
||||||
|
|
||||||
|
class Day13 implements Day {
|
||||||
|
|
||||||
|
part1(input: string[]): number | string {
|
||||||
|
|
||||||
|
const {dots, folds} = this.parseInput(input);
|
||||||
|
|
||||||
|
const foldedDots = dots.map(d => folds[0].apply(d));
|
||||||
|
|
||||||
|
return new Set(foldedDots.map(d => d.key())).size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
part2(input: string[]): number | string {
|
||||||
|
|
||||||
|
const {dots, folds} = this.parseInput(input);
|
||||||
|
|
||||||
|
let foldedDots = [...dots];
|
||||||
|
for (const fold of folds) {
|
||||||
|
|
||||||
|
foldedDots = foldedDots.map(d => fold.apply(d));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.renderDots(dots);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private parseInput(input: string[]): { dots: Vector2[], folds: Fold[] } {
|
||||||
|
const dots = input.filter(s => s.trim() !== "" && !s.startsWith("fold"))
|
||||||
|
.map(s => Vector2.parse(s));
|
||||||
|
|
||||||
|
const folds = input.filter(s => s.startsWith("fold"))
|
||||||
|
.map(s => Fold.parseInstruction(s));
|
||||||
|
return {dots, folds};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDots(dots: Vector2[]): string {
|
||||||
|
|
||||||
|
const minX = Math.min(...dots.map(d => d.x));
|
||||||
|
const maxX = Math.max(...dots.map(d => d.x));
|
||||||
|
const minY = Math.min(...dots.map(d => d.y));
|
||||||
|
const maxY = Math.max(...dots.map(d => d.y));
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
for (let y = minY; y <= maxY; y++) {
|
||||||
|
let line = "";
|
||||||
|
for (let x = minX; x <= maxX; x++) {
|
||||||
|
line += dots.some(d => d.x === x && d.y === y) ? "#" : ".";
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Fold {
|
||||||
|
axis: "x" | "y";
|
||||||
|
foldPosition: number;
|
||||||
|
|
||||||
|
constructor(axis: "x" | "y", position: number) {
|
||||||
|
this.axis = axis;
|
||||||
|
this.foldPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseInstruction(line: string): Fold {
|
||||||
|
if (line.startsWith("fold along y=")) {
|
||||||
|
return new Fold("y", parseInt(line.substr(13)));
|
||||||
|
} else if (line.startsWith("fold along x=")) {
|
||||||
|
return new Fold("x", parseInt(line.substr(13)));
|
||||||
|
} else {
|
||||||
|
throw Error(`Invalid fold instruction: "${line}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(pos: Vector2) {
|
||||||
|
|
||||||
|
if (this.axis === "y") {
|
||||||
|
|
||||||
|
return new Vector2(pos.x, this.foldAlong(pos.y));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return new Vector2(this.foldAlong(pos.x), pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private foldAlong(pos: number): number {
|
||||||
|
|
||||||
|
if (pos < this.foldPosition) return pos;
|
||||||
|
if (pos === this.foldPosition) console.log("Excuse me WTF?");
|
||||||
|
|
||||||
|
const distanceToFold = pos - this.foldPosition - 1;
|
||||||
|
return this.foldPosition - distanceToFold - 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Day13;
|
||||||
@@ -14,4 +14,4 @@ class DayX implements Day {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DayX;
|
export default DayX;
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import Day7 from "./day7";
|
|||||||
import Day8 from "./day8";
|
import Day8 from "./day8";
|
||||||
import Day9 from "./day9";
|
import Day9 from "./day9";
|
||||||
import Day10 from "./day10";
|
import Day10 from "./day10";
|
||||||
|
import Day11 from "./day11";
|
||||||
|
import Day12 from "./day12";
|
||||||
|
import Day13 from "./day13";
|
||||||
|
|
||||||
|
|
||||||
// // Start writing Firebase Functions
|
// // Start writing Firebase Functions
|
||||||
@@ -38,6 +41,9 @@ export const day = {
|
|||||||
8: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day8(), request, response) }),
|
8: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day8(), request, response) }),
|
||||||
9: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day9(), request, response) }),
|
9: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day9(), request, response) }),
|
||||||
10: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day10(), request, response) }),
|
10: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day10(), request, response) }),
|
||||||
|
11: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day11(), request, response) }),
|
||||||
|
12: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day12(), request, response) }),
|
||||||
|
13: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day13(), request, response) }),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,4 +60,4 @@ function sendResponse(response: Response, part1: string | number, part2: string
|
|||||||
|
|
||||||
const res: DayResult = { part1, part2 };
|
const res: DayResult = { part1, part2 };
|
||||||
response.send(res);
|
response.send(res);
|
||||||
}
|
}
|
||||||
|
|||||||
15
input/day/11-example.http
Normal file
15
input/day/11-example.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-11
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
5483143223
|
||||||
|
2745854711
|
||||||
|
5264556173
|
||||||
|
6141336146
|
||||||
|
6357385478
|
||||||
|
4167524645
|
||||||
|
2176841721
|
||||||
|
6882881134
|
||||||
|
4846848554
|
||||||
|
5283751526
|
||||||
|
|
||||||
|
###
|
||||||
15
input/day/11.http
Normal file
15
input/day/11.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-11
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
2524255331
|
||||||
|
1135625881
|
||||||
|
2838353863
|
||||||
|
1662312365
|
||||||
|
6847835825
|
||||||
|
2185684367
|
||||||
|
6874212831
|
||||||
|
5387247811
|
||||||
|
2255482875
|
||||||
|
8528557131
|
||||||
|
|
||||||
|
###
|
||||||
52
input/day/12-example.http
Normal file
52
input/day/12-example.http
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-12
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
start-A
|
||||||
|
start-b
|
||||||
|
A-c
|
||||||
|
A-b
|
||||||
|
b-d
|
||||||
|
A-end
|
||||||
|
b-end
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-12
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
dc-end
|
||||||
|
HN-start
|
||||||
|
start-kj
|
||||||
|
dc-start
|
||||||
|
dc-HN
|
||||||
|
LN-dc
|
||||||
|
HN-end
|
||||||
|
kj-sa
|
||||||
|
kj-HN
|
||||||
|
kj-dc
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-12
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
fs-end
|
||||||
|
he-DX
|
||||||
|
fs-he
|
||||||
|
start-DX
|
||||||
|
pj-DX
|
||||||
|
end-zg
|
||||||
|
zg-sl
|
||||||
|
zg-pj
|
||||||
|
pj-he
|
||||||
|
RW-he
|
||||||
|
fs-DX
|
||||||
|
pj-RW
|
||||||
|
zg-RW
|
||||||
|
start-pj
|
||||||
|
he-WI
|
||||||
|
zg-he
|
||||||
|
pj-fs
|
||||||
|
start-RW
|
||||||
|
|
||||||
|
###
|
||||||
30
input/day/12.http
Normal file
30
input/day/12.http
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-12
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
start-kc
|
||||||
|
pd-NV
|
||||||
|
start-zw
|
||||||
|
UI-pd
|
||||||
|
HK-end
|
||||||
|
UI-kc
|
||||||
|
pd-ih
|
||||||
|
ih-end
|
||||||
|
start-UI
|
||||||
|
kc-zw
|
||||||
|
end-ks
|
||||||
|
MF-mq
|
||||||
|
HK-zw
|
||||||
|
LF-ks
|
||||||
|
HK-kc
|
||||||
|
ih-HK
|
||||||
|
kc-pd
|
||||||
|
ks-pd
|
||||||
|
MF-pd
|
||||||
|
UI-zw
|
||||||
|
ih-NV
|
||||||
|
ks-HK
|
||||||
|
MF-kc
|
||||||
|
zw-NV
|
||||||
|
NV-ks
|
||||||
|
|
||||||
|
###
|
||||||
26
input/day/13-example.http
Normal file
26
input/day/13-example.http
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-13
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
6,10
|
||||||
|
0,14
|
||||||
|
9,10
|
||||||
|
0,3
|
||||||
|
10,4
|
||||||
|
4,11
|
||||||
|
6,0
|
||||||
|
6,12
|
||||||
|
4,1
|
||||||
|
0,13
|
||||||
|
10,12
|
||||||
|
3,4
|
||||||
|
3,0
|
||||||
|
8,4
|
||||||
|
1,10
|
||||||
|
2,14
|
||||||
|
8,10
|
||||||
|
9,0
|
||||||
|
|
||||||
|
fold along y=7
|
||||||
|
fold along x=5
|
||||||
|
|
||||||
|
###
|
||||||
1001
input/day/13.http
Normal file
1001
input/day/13.http
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user