[TASK] Implemented Day 16

This commit is contained in:
2021-12-16 22:54:40 +01:00
parent e3988e91b7
commit 1e405e982a
4 changed files with 207 additions and 0 deletions

150
functions/src/day16.ts Normal file
View File

@@ -0,0 +1,150 @@
import Day from "./day";
import Utils from "./utils";
class Day16 implements Day {
part1(input: string[]): number | string {
const packet = Packet.parse(input[0]);
return Day16.recursiveSumVersionNumbers(packet);
}
part2(input: string[]): number | string {
return Packet.parse(input[0]).calculateValue().toString();
}
static recursiveSumVersionNumbers(packet: Packet): number {
if (typeof packet.content === "bigint") {
return packet.version;
} else {
return packet.version + Utils.sum(packet.content.map(sp => Day16.recursiveSumVersionNumbers(sp)));
}
}
}
class Packet {
static readonly SUM_TYPE = 0
static readonly PROD_TYPE = 1;
static readonly MIN_TYPE = 2;
static readonly MAX_TYPE = 3;
static readonly LITERAL_TYPE = 4;
static readonly GT_TYPE = 5;
static readonly LT_TYPE = 6;
static readonly EQ_TYPE = 7;
static readonly VERSION_LENGTH = 3;
static readonly TYPE_LENGTH = 3;
static readonly LENGTH_TYPE_LENGTH = 1;
static readonly SUBPACKET_SIZE_LENGTH = 15;
static readonly SUBPACKET_COUNT_LENGTH = 11;
static readonly LITERAL_PART_LENGTH = 5;
version: number;
type: number;
content: Packet[] | bigint
binaryLength: number;
constructor(version: number, type: number, content: Packet[] | bigint, binaryLength: number) {
this.version = version;
this.type = type;
this.content = content;
this.binaryLength = binaryLength;
}
calculateValue(): bigint {
if (typeof this.content === "bigint") return this.content;
const subValues = this.content.map(c => c.calculateValue());
if (this.type === Packet.SUM_TYPE) {
return Utils.bigSum(subValues)
} else if (this.type === Packet.PROD_TYPE) {
return subValues.reduce((a, b) => a * b, 1n);
} else if (this.type === Packet.MIN_TYPE) {
return Utils.bigMin(subValues);
} else if (this.type === Packet.MAX_TYPE) {
return Utils.bigMax(subValues);
} else if (this.type === Packet.GT_TYPE) {
return subValues[0] > subValues[1] ? 1n : 0n;
} else if (this.type === Packet.LT_TYPE) {
return subValues[0] < subValues[1] ? 1n : 0n;
} else if (this.type === Packet.EQ_TYPE) {
return subValues[0] === subValues[1] ? 1n : 0n;
} else {
// Shouldn't happen
throw Error("Unsupported packet type: " + this.type);
}
}
static parse(input: string): Packet {
return this.parseBinaryInput(Packet.toBinary(input));
}
static toBinary(input: string): string {
return input.split("").map(s => parseInt(s, 16).toString(2).padStart(4, "0")).join("");
}
static parseBinaryInput(binaryInput: string, start: number = 0): Packet {
const version = parseInt(binaryInput.substr(start, Packet.VERSION_LENGTH), 2);
const type = parseInt(binaryInput.substr(start + Packet.VERSION_LENGTH, Packet.TYPE_LENGTH), 2);
const contentStart = start + Packet.VERSION_LENGTH + Packet.TYPE_LENGTH;
if (type === Packet.LITERAL_TYPE) {
// Literal value
let i = 0;
let binaryLiteral = "0b";
do {
binaryLiteral += binaryInput.substr(contentStart + (Packet.LITERAL_PART_LENGTH * i) + 1, Packet.LITERAL_PART_LENGTH - 1);
i++;
} while(binaryInput[contentStart + (Packet.LITERAL_PART_LENGTH * (i - 1))] === "1")
return new Packet(version, type, BigInt(binaryLiteral), Packet.VERSION_LENGTH + Packet.TYPE_LENGTH + (Packet.LITERAL_PART_LENGTH * i))
} else {
// Operator packets, so let's parse the subpackets:
const lengthType = binaryInput[contentStart];
if (lengthType === "0") {
const subpacketsLength = parseInt(binaryInput.substr(contentStart + Packet.LENGTH_TYPE_LENGTH, Packet.SUBPACKET_SIZE_LENGTH), 2);
const firstPacketStart = contentStart + Packet.LENGTH_TYPE_LENGTH + Packet.SUBPACKET_SIZE_LENGTH;
let curStart = firstPacketStart;
const subPackets = [];
while (curStart - firstPacketStart < subpacketsLength) {
const subPacket = this.parseBinaryInput(binaryInput, curStart);
curStart += subPacket.binaryLength;
subPackets.push(subPacket);
}
return new Packet(version, type, subPackets, curStart - start);
} else {
const subpacketCount = parseInt(binaryInput.substr(contentStart + Packet.LENGTH_TYPE_LENGTH, Packet.SUBPACKET_COUNT_LENGTH), 2);
let curStart = contentStart + Packet.LENGTH_TYPE_LENGTH + Packet.SUBPACKET_COUNT_LENGTH;
const subPackets = [];
for (let i = 0; i < subpacketCount; i++) {
const subPacket = this.parseBinaryInput(binaryInput, curStart);
curStart += subPacket.binaryLength;
subPackets.push(subPacket);
}
return new Packet(version, type, subPackets, curStart - start);
}
}
}
}
export default Day16;

View File

@@ -17,6 +17,7 @@ import Day12 from "./day12";
import Day13 from "./day13";
import Day14 from "./day14";
import Day15 from "./day15";
import Day16 from "./day16";
// // Start writing Firebase Functions
@@ -48,6 +49,7 @@ export const day = {
13: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day13(), request, response) }),
14: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day14(), request, response) }),
15: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day15(), request, response) }),
16: functions.region("europe-west1").https.onRequest((request, response) => { processDay(new Day16(), request, response) }),
}