Skip to content

Instantly share code, notes, and snippets.

@kwando

kwando/day18.exs Secret

Created December 18, 2017 17:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kwando/91574018e45ca7cce15c3d042a7c2f69 to your computer and use it in GitHub Desktop.
Save kwando/91574018e45ca7cce15c3d042a7c2f69 to your computer and use it in GitHub Desktop.
Day 17
defmodule AoC.Day18 do
def part1(instructions) do
program = load_program(instructions)
run_program(new_memory(), program)
end
def part2(instructions) do
program = load_program(instructions)
prog0 = new_memory() |> Map.put("p", 0) |> Map.put(:pid, 0)
prog1 = new_memory() |> Map.put("p", 1) |> Map.put(:pid, 1)
run_programs(program, prog0, prog1)
end
defp run_programs(_program, prog0 = %{rcv: true}, prog1 = %{rcv: true}) do
{:deadlock, prog0, prog1}
end
defp run_programs(program, prog0, prog1) do
case run_program(prog0, program) do
{:snd, value, prog0} ->
run_programs(program, %{prog1 | mbox: :queue.in(value, prog1.mbox), rcv: false }, prog0)
{:rcv, prog0} ->
run_programs(program, prog1, prog0)
end
end
defp new_memory() do
%{pc: 0, freq: 0, mbox: :queue.new, rcv: false, snd: nil, sent: 0}
end
defp load_program(instructions) do
Enum.with_index(instructions)
|> Enum.into(%{}, fn({x, y})-> {y, x} end)
end
defp run_program(mem = %{rcv: true}, _program) do
{:rcv, %{ mem | pc: mem.pc - 1}}
end
defp run_program(mem = %{snd: value}, _program) when is_integer(value) do
{:snd, value, %{ mem | snd: nil }}
end
defp run_program(memory, program) do
case Map.fetch(program, memory[:pc]) do
{:ok, instruction} ->
memory
|> run(instruction)
|> increment_program_counter()
|> run_program(program)
:error ->
{:terminated, memory}
end
end
defp inspect_memory(memory) do
registers = memory
|> Enum.filter(&match?({a, _} when is_binary(a) or is_atom(a), &1))
IO.inspect [
pc: memory[:pc],
freq: memory[:snd],
regs: registers
], [label: " mem"]
memory
end
defp increment_program_counter(registers), do: registers |> Map.update(:pc, 0, &( &1 + 1))
defp run(registers, {:set, [register, value]}) do
Map.put(registers, register, operand(registers, value))
end
defp run(registers, {:add, [register, value]}) do
Map.update(registers, register, value, fn(old_value)-> old_value + operand(registers, value) end)
end
defp run(registers, {:mul, [register, value]}) do
Map.update(registers, register, 0, fn(old_value)-> old_value * operand(registers, value) end)
end
defp run(registers, {:mod, [register, value]}) do
Map.update(registers, register, 0, &rem(&1, operand(registers, value)))
end
defp run(registers, {:snd, [register]}) do
value = operand(registers, register)
%{ registers | snd: value, sent: registers.sent + 1}
end
defp run(registers, {:rcv, [register]}) do
case :queue.out(registers.mbox) do
{{:value, value}, mbox} ->
registers
|> Map.put(:mbox, mbox)
|> Map.put(:rcv, false)
|> Map.put(register, value)
{:empty, _} ->
%{ registers | rcv: true }
end
end
defp run(registers, {:jgz, [x, y]}) do
if operand(registers, x) > 0 do
Map.update(registers, :pc, -1, &( &1 + operand(registers, y) - 1 ))
else
registers
end
end
defp operand(_registers, address) when is_integer(address), do: address
defp operand(registers, address) when is_binary(address), do: Map.get(registers, address, 0)
def parse_instruction(line) do
line
|> String.trim
|> String.split(" ")
|> case do
[instruction | args] ->
{String.to_atom(instruction), args |> Enum.map(&parse_literal/1)}
end
end
defp parse_literal(value) do
case Integer.parse(value) do
:error -> value
{integer, ""} -> integer
end
end
end
System.argv
|> List.first
|> File.stream!
|> Stream.map(&AoC.Day18.parse_instruction(&1))
|> AoC.Day18.part2
|> IO.inspect(label: "return")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment