Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
|
ea5a0ff8ed |
167
lib/day9/day9.ex
167
lib/day9/day9.ex
|
@ -65,13 +65,13 @@ defmodule Day9 do
|
|||
def repeat(_, 0), do: []
|
||||
def repeat(val, count), do: [val | repeat(val, count - 1)]
|
||||
|
||||
def run(state, parent, ip \\ 0)
|
||||
def run(state, parent, ip \\ 0, debug \\ false)
|
||||
|
||||
def run(memory, parent, ip) when is_list(memory) do
|
||||
run({memory, 0}, parent, ip)
|
||||
def run(memory, parent, ip, debug) when is_list(memory) do
|
||||
run({memory, 0}, parent, ip, debug)
|
||||
end
|
||||
|
||||
def run({memory, _relative_base} = state, parent, ip) when ip < length(memory) do
|
||||
def run({memory, _relative_base} = state, parent, ip, debug) when ip < length(memory) do
|
||||
# IO.puts("IP: #{ip}")
|
||||
# IO.inspect(memory)
|
||||
|
||||
|
@ -80,14 +80,34 @@ defmodule Day9 do
|
|||
send(parent, {:halt, self(), memory})
|
||||
|
||||
{state, :cont, offset} ->
|
||||
run(state, parent, ip + offset)
|
||||
if debug do
|
||||
receive do
|
||||
:step ->
|
||||
run(state, parent, ip + offset)
|
||||
|
||||
:abort ->
|
||||
send(parent, {:abort, self(), state})
|
||||
end
|
||||
else
|
||||
run(state, parent, ip + offset)
|
||||
end
|
||||
|
||||
{state, :jump, ip} ->
|
||||
run(state, parent, ip)
|
||||
if debug do
|
||||
receive do
|
||||
:step ->
|
||||
run(state, parent, ip)
|
||||
|
||||
:abort ->
|
||||
send(parent, {:abort, self(), state})
|
||||
end
|
||||
else
|
||||
run(state, parent, ip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run(state, parent, _) do
|
||||
def run(state, parent, _, _) do
|
||||
send(parent, {:ok, self(), state})
|
||||
end
|
||||
|
||||
|
@ -101,9 +121,9 @@ defmodule Day9 do
|
|||
place = param + 2
|
||||
|
||||
case op |> div(pow(10, place)) |> rem(10) do
|
||||
0 -> Enum.at(memory, val)
|
||||
1 -> val
|
||||
2 -> Enum.at(memory, relative_base + val)
|
||||
0 -> {Enum.at(memory, val), {:position, val}}
|
||||
1 -> {val, {:immediate, val}}
|
||||
2 -> {Enum.at(memory, relative_base + val), {:relative, val}}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -111,8 +131,8 @@ defmodule Day9 do
|
|||
place = param + 2
|
||||
|
||||
case op |> div(pow(10, place)) |> rem(10) do
|
||||
2 -> relative_base + val
|
||||
_ -> val
|
||||
2 -> {relative_base + val, {:relative, val}}
|
||||
_ -> {val, {:immediate, val}}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -123,31 +143,38 @@ defmodule Day9 do
|
|||
end
|
||||
|
||||
# halt
|
||||
def eval([99 | _], memory, _) do
|
||||
def eval([99 | _], memory, parent) do
|
||||
send(parent, {:debug, "Halted", [], memory})
|
||||
{memory, :halt}
|
||||
end
|
||||
|
||||
# add
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, _) when opcode(op, 1) do
|
||||
a_val = get_param(op, 0, a, state)
|
||||
b_val = get_param(op, 1, b, state)
|
||||
dest = get_write_param(op, 2, dest, state)
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, parent) when opcode(op, 1) do
|
||||
{a_val, a_param} = get_param(op, 0, a, state)
|
||||
{b_val, b_param} = get_param(op, 1, b, state)
|
||||
{dest, dest_param} = get_write_param(op, 2, dest, state)
|
||||
new_state = {List.replace_at(memory, dest, a_val + b_val), relative_base}
|
||||
|
||||
send(parent, {:debug, "Add", [a_param, b_param, dest_param], new_state})
|
||||
|
||||
{
|
||||
{List.replace_at(memory, dest, a_val + b_val), relative_base},
|
||||
new_state,
|
||||
:cont,
|
||||
4
|
||||
}
|
||||
end
|
||||
|
||||
# multiply
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, _) when opcode(op, 2) do
|
||||
a_val = get_param(op, 0, a, state)
|
||||
b_val = get_param(op, 1, b, state)
|
||||
dest = get_write_param(op, 2, dest, state)
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, parent) when opcode(op, 2) do
|
||||
{a_val, a_param} = get_param(op, 0, a, state)
|
||||
{b_val, b_param} = get_param(op, 1, b, state)
|
||||
{dest, dest_param} = get_write_param(op, 2, dest, state)
|
||||
new_state = {List.replace_at(memory, dest, a_val * b_val), relative_base}
|
||||
|
||||
send(parent, {:debug, "Multiply", [a_param, b_param, dest_param], new_state})
|
||||
|
||||
{
|
||||
{List.replace_at(memory, dest, a_val * b_val), relative_base},
|
||||
new_state,
|
||||
:cont,
|
||||
4
|
||||
}
|
||||
|
@ -155,7 +182,7 @@ defmodule Day9 do
|
|||
|
||||
# input
|
||||
def eval([op, addr | _], {memory, relative_base} = state, parent) when opcode(op, 3) do
|
||||
addr = get_write_param(op, 0, addr, state)
|
||||
{addr, addr_param} = get_write_param(op, 0, addr, state)
|
||||
send(parent, {:in, self()})
|
||||
|
||||
res =
|
||||
|
@ -163,8 +190,12 @@ defmodule Day9 do
|
|||
{:in, val} -> val
|
||||
end
|
||||
|
||||
new_state = {List.replace_at(memory, addr, res), relative_base}
|
||||
|
||||
send(parent, {:debug, "Input", [addr_param], new_state})
|
||||
|
||||
{
|
||||
{List.replace_at(memory, addr, res), relative_base},
|
||||
new_state,
|
||||
:cont,
|
||||
2
|
||||
}
|
||||
|
@ -172,68 +203,92 @@ defmodule Day9 do
|
|||
|
||||
# output
|
||||
def eval([op, param | _], state, parent) when opcode(op, 4) do
|
||||
out = get_param(op, 0, param, state)
|
||||
{out, out_param} = get_param(op, 0, param, state)
|
||||
send(parent, {:out, self(), out})
|
||||
|
||||
send(parent, {:debug, "Output", [out_param], state})
|
||||
{state, :cont, 2}
|
||||
end
|
||||
|
||||
# jump if non-zero
|
||||
def eval([op, condition, ip | _], state, _) when opcode(op, 5) do
|
||||
case get_param(op, 0, condition, state) do
|
||||
0 ->
|
||||
{state, :cont, 3}
|
||||
def eval([op, condition, ip | _], state, parent) when opcode(op, 5) do
|
||||
{cond_val, cond_param} = get_param(op, 0, condition, state)
|
||||
{dest_val, dest_param} = get_param(op, 1, ip, state)
|
||||
|
||||
_ ->
|
||||
{state, :jump, get_param(op, 1, ip, state)}
|
||||
end
|
||||
new_state =
|
||||
case cond_val do
|
||||
0 ->
|
||||
{state, :cont, 3}
|
||||
|
||||
_ ->
|
||||
{state, :jump, dest_val}
|
||||
end
|
||||
|
||||
send(parent, {:debug, "Jump if non-zero", [cond_param, dest_param], new_state})
|
||||
new_state
|
||||
end
|
||||
|
||||
# jump if zero
|
||||
def eval([op, condition, ip | _], state, _) when opcode(op, 6) do
|
||||
case get_param(op, 0, condition, state) do
|
||||
0 ->
|
||||
{state, :jump, get_param(op, 1, ip, state)}
|
||||
def eval([op, condition, ip | _], state, parent) when opcode(op, 6) do
|
||||
{cond_val, cond_param} = get_param(op, 0, condition, state)
|
||||
{dest_val, dest_param} = get_param(op, 1, ip, state)
|
||||
|
||||
_ ->
|
||||
{state, :cont, 3}
|
||||
end
|
||||
new_state =
|
||||
case cond_val do
|
||||
0 ->
|
||||
{state, :jump, dest_val}
|
||||
|
||||
_ ->
|
||||
{state, :cont, 3}
|
||||
end
|
||||
|
||||
send(parent, {:debug, "Jump if zero", [cond_param, dest_param], new_state})
|
||||
new_state
|
||||
end
|
||||
|
||||
# less than
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, _) when opcode(op, 7) do
|
||||
a_val = get_param(op, 0, a, state)
|
||||
b_val = get_param(op, 1, b, state)
|
||||
dest = get_write_param(op, 2, dest, state)
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, parent) when opcode(op, 7) do
|
||||
{a_val, a_param} = get_param(op, 0, a, state)
|
||||
{b_val, b_param} = get_param(op, 1, b, state)
|
||||
{dest, dest_param} = get_write_param(op, 2, dest, state)
|
||||
|
||||
memory =
|
||||
new_state = {
|
||||
if a_val < b_val do
|
||||
List.replace_at(memory, dest, 1)
|
||||
else
|
||||
List.replace_at(memory, dest, 0)
|
||||
end
|
||||
end,
|
||||
relative_base
|
||||
}
|
||||
|
||||
{{memory, relative_base}, :cont, 4}
|
||||
send(parent, {:debug, "Less than", [a_param, b_param, dest_param], new_state})
|
||||
{new_state, :cont, 4}
|
||||
end
|
||||
|
||||
# equals
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, _) when opcode(op, 8) do
|
||||
a_val = get_param(op, 0, a, state)
|
||||
b_val = get_param(op, 1, b, state)
|
||||
dest = get_write_param(op, 2, dest, state)
|
||||
def eval([op, a, b, dest | _], {memory, relative_base} = state, parent) when opcode(op, 8) do
|
||||
{a_val, a_param} = get_param(op, 0, a, state)
|
||||
{b_val, b_param} = get_param(op, 1, b, state)
|
||||
{dest, dest_param} = get_write_param(op, 2, dest, state)
|
||||
|
||||
memory =
|
||||
new_state = {
|
||||
if a_val == b_val do
|
||||
List.replace_at(memory, dest, 1)
|
||||
else
|
||||
List.replace_at(memory, dest, 0)
|
||||
end
|
||||
end,
|
||||
relative_base
|
||||
}
|
||||
|
||||
{{memory, relative_base}, :cont, 4}
|
||||
send(parent, {:debug, "Equal to", [a_param, b_param, dest_param], new_state})
|
||||
{new_state, :cont, 4}
|
||||
end
|
||||
|
||||
# set relative base
|
||||
def eval([op, new_base | _], {memory, relative_base} = state, _) when opcode(op, 9) do
|
||||
{{memory, relative_base + get_param(op, 0, new_base, state)}, :cont, 2}
|
||||
def eval([op, new_base | _], {memory, relative_base} = state, parent) when opcode(op, 9) do
|
||||
{new_base_val, new_base_param} = get_param(op, 0, new_base, state)
|
||||
new_state = {memory, relative_base + new_base_val}
|
||||
send(parent, {:debug, "Set relative base", [new_base_param], new_state})
|
||||
{new_state, :cont, 2}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -225,6 +225,22 @@ defmodule Assembler do
|
|||
add #{a}, $#{dest}, #{dest}
|
||||
"""
|
||||
|
||||
assemble_macro ["div", a, b, dest],
|
||||
"""
|
||||
mov 0, #{dest}
|
||||
mov #{a}, tmp
|
||||
do_sub:
|
||||
clt $tmp, #{b}, _self + 2
|
||||
jnz -1, end
|
||||
add 1, $#{dest}, #{dest}
|
||||
sub $tmp, #{b}, tmp
|
||||
jmp do_sub
|
||||
|
||||
tmp: -1
|
||||
end:
|
||||
"""
|
||||
|> IO.puts()
|
||||
|
||||
assemble_macro ["not", src, dest],
|
||||
"""
|
||||
sub 1, #{src}, #{dest}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
defmodule Debugger do
|
||||
def run() do
|
||||
program = [1, 1, 2, 3, 1102, 4, 5, 0, 99]
|
||||
memory_view_length = floor(columns() / 7) * floor(rows() / 2 - 10)
|
||||
memory = Day9.expand_memory(program, memory_view_length)
|
||||
|
||||
parent = self()
|
||||
|
||||
pid =
|
||||
spawn(fn ->
|
||||
Day9.run(memory, parent, 0, true)
|
||||
end)
|
||||
|
||||
step(pid)
|
||||
end
|
||||
|
||||
def columns do
|
||||
{:ok, cols} = :io.columns()
|
||||
cols
|
||||
end
|
||||
|
||||
def rows do
|
||||
{:ok, rows} = :io.rows()
|
||||
rows
|
||||
end
|
||||
|
||||
def step(pid) do
|
||||
IO.write([IO.ANSI.clear(), IO.ANSI.home()])
|
||||
|
||||
receive do
|
||||
{:debug, msg, params, {memory, _}} ->
|
||||
print_memory(memory)
|
||||
IO.puts("#{msg}: #{inspect(params)}")
|
||||
IO.gets("")
|
||||
send(pid, :step)
|
||||
step(pid)
|
||||
|
||||
{msg, _, {memory, _}} when msg in [:halt, :abort, :ok] ->
|
||||
print_memory(memory)
|
||||
IO.gets("")
|
||||
end
|
||||
end
|
||||
|
||||
def print_memory(memory, row_size \\ nil)
|
||||
|
||||
def print_memory([], _) do
|
||||
end
|
||||
|
||||
def print_memory(memory, row_size) when is_nil(row_size) do
|
||||
print_memory(memory, floor(columns() / 7))
|
||||
end
|
||||
|
||||
def print_memory(memory, row_size) do
|
||||
memory
|
||||
|> Enum.take(row_size)
|
||||
|> Enum.each(fn val ->
|
||||
val
|
||||
|> to_string()
|
||||
|> String.pad_leading(7)
|
||||
|> IO.write()
|
||||
end)
|
||||
|
||||
IO.write("\n\n")
|
||||
|
||||
print_memory(Enum.drop(memory, row_size), row_size)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
program:
|
||||
data 1, 1, 2, 3
|
Loading…
Reference in New Issue