[TASK] Implemented Day 16
This commit is contained in:
150
functions/src/day16.ts
Normal file
150
functions/src/day16.ts
Normal 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;
|
||||
|
||||
@@ -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) }),
|
||||
|
||||
}
|
||||
|
||||
|
||||
48
input/day/16-example.http
Normal file
48
input/day/16-example.http
Normal file
@@ -0,0 +1,48 @@
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
D2FE28
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
38006F45291200
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
EE00D40C823060
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
8A004A801A8002F478
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
620080001611562C8802118E34
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
C0015000016115A2E0802F182340
|
||||
|
||||
###
|
||||
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
A0016C880162017C3686B18A3D4780
|
||||
|
||||
###
|
||||
7
input/day/16.http
Normal file
7
input/day/16.http
Normal file
@@ -0,0 +1,7 @@
|
||||
POST http://localhost:5001/advent-of-code-2021-911a8/europe-west1/day-16
|
||||
Content-Type: text/plain
|
||||
|
||||
4054460802532B12FEE8B180213B19FA5AA77601C010E4EC2571A9EDFE356C7008E7B141898C1F4E50DA7438C011D005E4F6E727B738FC40180CB3ED802323A8C3FED8C4E8844297D88C578C26008E004373BCA6B1C1C99945423798025800D0CFF7DC199C9094E35980253FB50A00D4C401B87104A0C8002171CE31C41201062C01393AE2F5BCF7B6E969F3C553F2F0A10091F2D719C00CD0401A8FB1C6340803308A0947B30056803361006615C468E4200E47E8411D26697FC3F91740094E164DFA0453F46899015002A6E39F3B9802B800D04A24CC763EDBB4AFF923A96ED4BDC01F87329FA491E08180253A4DE0084C5B7F5B978CC410012F9CFA84C93900A5135BD739835F00540010F8BF1D22A0803706E0A47B3009A587E7D5E4D3A59B4C00E9567300AE791E0DCA3C4A32CDBDC4830056639D57C00D4C401C8791162380021108E26C6D991D10082549218CDC671479A97233D43993D70056663FAC630CB44D2E380592FB93C4F40CA7D1A60FE64348039CE0069E5F565697D59424B92AF246AC065DB01812805AD901552004FDB801E200738016403CC000DD2E0053801E600700091A801ED20065E60071801A800AEB00151316450014388010B86105E13980350423F447200436164688A4001E0488AC90FCDF31074929452E7612B151803A200EC398670E8401B82D04E31880390463446520040A44AA71C25653B6F2FE80124C9FF18EDFCA109275A140289CDF7B3AEEB0C954F4B5FC7CD2623E859726FB6E57DA499EA77B6B68E0401D996D9C4292A881803926FB26232A133598A118023400FA4ADADD5A97CEEC0D37696FC0E6009D002A937B459BDA3CC7FFD65200F2E531581AD80230326E11F52DFAEAAA11DCC01091D8BE0039B296AB9CE5B576130053001529BE38CDF1D22C100509298B9950020B309B3098C002F419100226DC
|
||||
|
||||
###
|
||||
|
||||
Reference in New Issue
Block a user