Day 24

import Solution from "./solution.ts";

class Gate {
  #out: string;
  #type: "AND" | "XOR" | "OR";
  #ins: Record<string, string> = {};

  constructor(type: "AND" | "XOR" | "OR", out: string) {
    this.#out = out;
    this.#type = type;
  }

  #compute() {
    switch (this.#type) {
      case "AND":
        return Object.values(this.#ins).every((n) => n === "1");
      case "OR":
        return Object.values(this.#ins).some((n) => n === "1");
      case "XOR": {
        const [v1, v2] = Object.values(this.#ins);
        return v1 !== v2;
      }
    }
  }

  in(name: string, value: string) {
    this.#ins[name] = value;
    if (Object.keys(this.#ins).length !== 2) {
      return null;
    }
    return [this.#out, this.#compute() ? "1" : "0"];
  }

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

const task = new Solution(
  (arr: string[][]) => {
    const gates = new Map<string, Gate[]>();
    const z = new Map<string, string>();
    for (const def of arr[1]) {
      const [i1, type, i2, _, out] = def.split(" ");
      const gate = new Gate(type as "AND" | "OR" | "XOR", out);
      gates.set(i1, (gates.get(i1) ?? []).concat([gate]));
      gates.set(i2, (gates.get(i2) ?? []).concat([gate]));
    }
    const ins = arr[0].map((n) => n.split(": "));
    while (ins.length > 0) {
      const [name, value] = ins.shift()!;
      if (name.startsWith("z")) {
        z.set(name, value);
      }
      for (const gate of (gates.get(name) ?? [])) {
        const o = gate.in(name, value);
        if (o !== null) {
          ins.push(o);
        }
      }
    }
    return Number.parseInt(
      z.entries().toArray().sort(([k1], [k2]) => k2.localeCompare(k1)).map((
        [, v],
      ) => v).join(""),
      2,
    );
  },
  (arr: string[][]) => {
    if (isTest) return "";
    // https://www.reddit.com/r/adventofcode/comments/1hl698z/comment/m3kt1je
    const wrong = new Set<string>();
    const gates = new Map<string, Gate[]>();
    let highestZ = 0;
    for (const def of arr[1]) {
      const [i1, type, i2, _, out] = def.split(" ");
      const gate = new Gate(type as "AND" | "OR" | "XOR", out);
      gates.set(i1, (gates.get(i1) ?? []).concat([gate]));
      gates.set(i2, (gates.get(i2) ?? []).concat([gate]));
      if (out.startsWith("z")) {
        highestZ = Math.max(Number.parseInt(out.slice(1)), highestZ);
      }
    }
    for (const def of arr[1]) {
      const [i1, type, i2, _, out] = def.split(" ");
      if (
        out.startsWith("z") && type != "XOR" &&
        !out.endsWith(highestZ.toString())
      ) {
        wrong.add(out);
      }
      if (
        type === "XOR" && [i1, i2, out].every((c) => !/^[xyz]/.test(c))
      ) {
        wrong.add(out);
      }
      if (type === "AND" && ![i1, i2].includes("x00")) {
        for (const g of gates.get(out) ?? []) {
          if (g.type !== "OR") {
            wrong.add(out);
          }
        }
      }
      if (type === "XOR") {
        for (const g of gates.get(out) ?? []) {
          if (g.type === "OR") {
            wrong.add(out);
          }
        }
      }
    }
    return wrong.values().toArray().sort().join(",");
  },
  {
    sep: "\n\n",
    transform: (s) => s.split("\n"),
  },
);
task.expect(2024, "");

export default task;

Last edited 04. April 2025 13:29