Day 16

import Solution from "./solution.ts";

type Packet = {
  version: number;
  typeId: number;
  subPackets: Packet[];
  value: number;
};

class Reader {
  #cursor = 0;
  #string: string;
  #stamp = [0];

  constructor(s: string) {
    this.#string = s
      .split("")
      .map((n) => Number.parseInt(n, 16).toString(2).padStart(4, "0"))
      .join("");
  }

  take(n = 1) {
    this.#cursor += n;
    return this.#string.slice(this.#cursor - n, this.#cursor);
  }

  isEoL() {
    return this.#cursor > this.#string.length;
  }

  get cursor() {
    return this.#cursor;
  }

  stamp() {
    this.#stamp.push(this.#cursor);
  }

  since() {
    return this.#cursor - this.#stamp[this.#stamp.length - 1];
  }

  pop() {
    this.#stamp.pop();
  }
}

function parsePacket(
  reader: Reader,
  opts: { type: "0"; subLength: number } | { type: "1"; subPackets: number } = {
    type: "1",
    subPackets: 1,
  }
) {
  const p: Packet[] = [];
  if (opts.type === "0") reader.stamp();
  while (
    (opts.type === "0"
      ? reader.since() < opts.subLength
      : p.length < opts.subPackets) &&
    !reader.isEoL()
  ) {
    const version = Number.parseInt(reader.take(3), 2);
    const typeId = Number.parseInt(reader.take(3), 2);
    switch (typeId) {
      case 4: {
        let value = "";
        while (reader.take() === "1") {
          value += reader.take(4);
        }
        value += reader.take(4);
        p.push({
          version,
          typeId,
          value: Number.parseInt(value, 2),
          subPackets: [],
        });
        break;
      }
      default: {
        let packets: Packet[] = [];
        switch (reader.take()) {
          case "0": {
            packets = parsePacket(reader, {
              type: "0",
              subLength: Number.parseInt(reader.take(15), 2),
            });
            break;
          }
          case "1": {
            packets = parsePacket(reader, {
              type: "1",
              subPackets: Number.parseInt(reader.take(11), 2),
            });
            break;
          }
        }
        let value = 0;
        switch (typeId) {
          case 0: {
            value = packets.reduce((p, c) => p + c.value, 0);
            break;
          }
          case 1: {
            value = packets.reduce((p, c) => p * c.value, 1);
            break;
          }
          case 2: {
            value = Math.min(...packets.map((c) => c.value));
            break;
          }
          case 3: {
            value = Math.max(...packets.map((c) => c.value));
            break;
          }
          case 5: {
            value = packets[0].value > packets[1].value ? 1 : 0;
            break;
          }
          case 6: {
            value = packets[0].value < packets[1].value ? 1 : 0;
            break;
          }
          case 7: {
            value = packets[0].value === packets[1].value ? 1 : 0;
            break;
          }
        }
        p.push({ version, typeId, subPackets: packets, value });
        break;
      }
    }
  }
  if (opts.type === "0") reader.pop();
  return p;
}

const task = new Solution(
  (arr: Reader[]) => {
    const r = parsePacket(arr[0])[0];
    const sum = (r: Packet): number =>
      r.typeId === 4
        ? r.version
        : r.version + r.subPackets!.reduce((p, c) => p + sum(c), 0);
    return sum(r);
  },
  (arr: Reader[]) => {
    const r = parsePacket(arr[0]);
    return r[0].value;
  },
  {
    transform: (a) => new Reader(a),
  }
);
task.expect(31, 54);

export default task;

Last edited 04. April 2025 13:29