advent_of_code/elixir/livebook/2024/day24.livemd

2.8 KiB

AOC 2024 Day 24

Section

example_input = """
x00: 1
x01: 0
x02: 1
x03: 1
x04: 0
y00: 1
y01: 1
y02: 1
y03: 1
y04: 1

ntg XOR fgs -> mjb
y02 OR x01 -> tnw
kwq OR kpj -> z05
x00 OR x03 -> fst
tgd XOR rvg -> z01
vdt OR tnw -> bfw
bfw AND frj -> z10
ffh OR nrd -> bqk
y00 AND y03 -> djm
y03 OR y00 -> psh
bqk OR frj -> z08
tnw OR fst -> frj
gnj AND tgd -> z11
bfw XOR mjb -> z00
x03 OR x00 -> vdt
gnj AND wpb -> z02
x04 AND y00 -> kjc
djm OR pbm -> qhw
nrd AND vdt -> hwm
kjc AND fst -> rvg
y04 OR y02 -> fgs
y01 AND x02 -> pbm
ntg OR kjc -> kwq
psh XOR fgs -> tgd
qhw XOR tgd -> z09
pbm OR djm -> kpj
x03 XOR y03 -> ffh
x00 XOR y04 -> ntg
bfw OR bqk -> z06
nrd XOR fgs -> wpb
frj XOR qhw -> z04
bqk OR frj -> z07
y03 OR x01 -> nrd
hwm AND bqk -> z03
tgd XOR rvg -> z12
tnw OR pbm -> gnj
"""
defmodule CrossedWires do
  import Bitwise
  def gate(a, b, :or), do: bor(a, b)
  def gate(a, b, :and), do: a &&& b
  def gate(a, b, :xor), do: bxor(a, b)
  defmacro defgate(arg1, arg2, operation, output) do
    quote do
      def unquote(output)() do
        gate(
          unquote(arg1)(),
          unquote(arg2)(),
          unquote(operation)
        )
      end
    end
  end
  
  defmacro defwire(label, int, value) do
    f_name = "#{label |> Atom.to_string()}#{int |> to_string() |> String.pad_leading(2, "0")}"
    quote do
      def unquote(f_name |> String.to_atom())(), do: unquote(value)
    end
  end

  def transpile(input) do
    lines = input 
    |> String.split("\n", trim: true)
    |> Stream.reject(&(&1 == ""))

    all_zs = lines 
      |> Stream.filter(&(String.contains?(&1, "-> z")))
      |> Stream.map(&Enum.at(String.split(&1, " "), 4))
      |> Enum.sort()
  calls = all_zs |> Enum.map(fn z -> "\#{#{z}()}" end) |> Enum.join("")
  "defmodule MyCrossedWires do\nimport CrossedWires\n" <> 
      (lines
        |> Enum.map(fn line -> 
          transpile_line(line)
        end)
        |> Enum.join("\n")
      )
      <> 
      "\n" <>
      "def z() do\n" <>
      "\"#{calls}\"\nend\n" <>
        "def part1() do\n" <>
          "z() |> String.reverse() |> String.to_integer(2)\n" <>
            "end\n"
      <> "\n end"
  end
  
  def transpile_line(line) do
    if String.ends_with?(line, ": 0") or String.ends_with?(line, ": 1") do
      transpile_defwire(line)
    else
      transpile_defgate(line)
    end
  end

  def transpile_defwire(<<flavor::binary-size(1)>> <> <<i::binary-size(2)>> <> ": " <> value) do
    "defwire(:#{flavor},#{i},#{value})"
  end

  def transpile_defgate(line) do
    [arg1, op, arg2, _, output] = line |> String.split(" ")
    "defgate(:#{arg1}, :#{arg2}, :#{op |> String.downcase()}, :#{output})"
  end
end
CrossedWires.transpile(example_input) |> IO.puts()
# paste transpiled output here
MyCrossedWires.part1()