defmodule Day17 do def run do [registers, program] = File.read!("data.txt") |> String.trim() |> String.split("\n\n") |> Enum.with_index() |> Enum.map(fn {lines, idx} -> if idx == 0, do: parseRegisters(lines), else: parseProgram(lines) end) # registers = %{A: 2024, B: 0, C: 0} # program = [0, 1, 5, 4, 3, 0] initial_state = %{ program: program, registers: registers, pointer: 0, output: [] } dbg(initial_state) state = run(initial_state) output = Enum.reverse(state.output) dbg(output) # part 2 # target is [2, 4, 1, 6, 7, 5, 4, 4, 1, 7, 0, 3, 5, 5, 3, 0] # noticing every power of 8 it adds a digit # the new big digit goes [1], 0, 3, 2, 4, 4, 1, 5 # when there's 1 digit, the biggest digit changes every 1 # when there are 2 digits, the biggest digit changes every 8 # when there are 3 digits, the biggest digit changes every 8 * 8 # etc. # when there are 16 digits, the biggest digit changes every 8 ^ 15 # if the first digit is 2, that's the 3rd in the sequence, so 3x that # # 1 0 3 2 4 4 1 5 # when 2 digits, the smaller digit goes: # 0: 1 0 3 2 6 5 1 1 # 3: 1 0 2 2 0 6 1 5 # 2: 1 0 2 2 2 7 1 1 # 4: 1 0 1 3 4 0 1 5 # 4: 1 0 1 3 6 1 1 1 # 1: 1 0 0 3 0 2 1 5 # 5: 1 0 0 3 2 3 1 1 # # when 3 digits, smallest digit goes # 0 0 7 0 4 4 1 5 # # starter = 3 * 8 ** 15 + 6 * 8 ** 14 + 6 * 8 ** 13 # interesting, all ones starter = 2 * 8 ** 15 increment = 8 ** 10 try(starter, initial_state, increment) end defp try(a, state, increment) do # IO.gets("") new_state = %{state | registers: %{state.registers | A: a}} val = run(new_state) # if Integer.mod(a, 1000) == 0 do IO.puts(a) dbg(a) dbg(val) # end if Enum.reverse(val.output) == state.program do a else try(a + increment, state, increment) end end defp run( %{ program: program, registers: registers, pointer: pointer, output: output } = state ) do opcode = Enum.at(program, pointer) operand = Enum.at(program, pointer + 1) # dbg({"run", state}) if is_nil(opcode) do state else new_state = case opcode do # adv 0 -> num = registers[:A] den = Integer.pow(2, getComboOperandValue(operand, registers)) new_regs = %{registers | A: trunc(num / den)} %{state | registers: new_regs, pointer: pointer + 2} # bxl 1 -> new_regs = %{registers | B: Bitwise.bxor(registers[:B], operand)} %{state | registers: new_regs, pointer: pointer + 2} # bst 2 -> new_regs = %{ registers | B: Integer.mod(getComboOperandValue(operand, registers), 8) } %{state | registers: new_regs, pointer: pointer + 2} # jnz 3 -> if registers[:A] == 0 do %{state | pointer: pointer + 2} else %{state | pointer: operand} end # bxc 4 -> new_regs = %{registers | B: Bitwise.bxor(registers[:B], registers[:C])} %{state | registers: new_regs, pointer: pointer + 2} # out 5 -> val = Integer.mod(getComboOperandValue(operand, registers), 8) %{state | pointer: pointer + 2, output: [val | output]} # bdv 6 -> num = registers[:A] den = Integer.pow(2, getComboOperandValue(operand, registers)) new_regs = %{registers | B: trunc(num / den)} %{state | registers: new_regs, pointer: pointer + 2} # cdv 7 -> num = registers[:A] den = Integer.pow(2, getComboOperandValue(operand, registers)) new_regs = %{registers | C: trunc(num / den)} %{state | registers: new_regs, pointer: pointer + 2} end run(new_state) end end defp parseProgram(line) do [_header, digits] = String.split(line, " ") digits |> String.split(",") |> Enum.map(&String.to_integer/1) end defp getComboOperandValue(op, registers) do case op do o when o <= 3 -> op 4 -> registers[:A] 5 -> registers[:B] 6 -> registers[:C] end end defp parseRegisters(lines) do lines |> String.split("\n") |> Enum.map(&String.split(&1, " ")) |> Enum.reduce(%{}, fn [_header, label, value], acc -> atom = String.trim(label, ":") |> String.to_atom() Map.put(acc, atom, String.to_integer(value)) end) end end Day17.run()