WFLILUZIPJ4S2PGS5VTH5DM4U3VFGME5O6U3VJB6Y5Q727SFLZMQC defmodule ProgramTest douse ExUnit.Casetest "parse program" doexample_string = File.read!("example")parsed_program =String.split(example_string, "\n", trim: true)|> Enum.map(&Operation.parse/1)assert Program.parse(example_string) == parsed_programendtest "decorruptions" doassert Program.decorruptions([]) == [[]]assert Program.decorruptions([{:acc, 3}]) == [[{:acc, 3}]]assert Program.decorruptions([{:nop, 3}]) == [[{:nop, 3}], [{:jmp, 3}]]assert Program.decorruptions([{:jmp, 3}]) == [[{:jmp, 3}], [{:nop, 3}]]endend
defmodule OperationTest douse ExUnit.Casetest "parse operation" doassert Operation.parse("nop +0") == {:nop, 0}assert Operation.parse("acc +1") == {:acc, 1}assert Operation.parse("jmp +4") == {:jmp, 4}assert Operation.parse("jmp -3") == {:jmp, -3}endend
defmodule MachineTest douse ExUnit.Casetest "new machine has ip 0" doassert Machine.init().ip == 0endtest "new machine has acc 0" doassert Machine.init().acc == 0endtest "init machine with program" doexample_program = Program.parse(File.read!("example"))machine = Machine.init(example_program)assert machine.program == example_programendtest "operation NOP" donext = Machine.init() |> Machine.apply({:nop, 0})assert next.ip == 1assert next.acc == 0endtest "operation ACC" donext = Machine.init() |> Machine.apply({:acc, 23})assert next.ip == 1assert next.acc == 23endtest "operation JMP" donext = Machine.init() |> Machine.apply({:jmp, 22})assert next.ip == 22assert next.acc == 0endtest "eof" domachine = [{:acc, 3}] |> Machine.init()assert machine.acc == 0assert machine.halt == falseassert machine.eof == falsemachine = machine |> Machine.run()assert machine.acc == 3assert machine.halt == trueassert machine.eof == trueendend
test "operation NOP" donext = Machine.init() |> Machine.apply({:nop})assert next.ip == 1assert next.acc == 0endtest "operation ACC" donext = Machine.init() |> Machine.apply({:acc, 23})assert next.ip == 1assert next.acc == 23endtest "operation JMP" donext = Machine.init() |> Machine.apply({:jmp, 22})assert next.ip == 22assert next.acc == 0endtest "parse operation" doassert HandheldHalting.parse_operation("nop +0") == {:nop}assert HandheldHalting.parse_operation("acc +1") == {:acc, 1}assert HandheldHalting.parse_operation("jmp +4") == {:jmp, 4}assert HandheldHalting.parse_operation("jmp -3") == {:jmp, -3}endtest "parse program" doexample_string = File.read!("example")parsed_program =String.split(example_string, "\n", trim: true)|> Enum.map(&HandheldHalting.parse_operation/1)assert HandheldHalting.parse_program(example_string) == parsed_programendtest "init machine with program" doexample_program = HandheldHalting.parse_program(File.read!("example"))machine = Machine.init(example_program)assert machine.program == example_programend
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
defmodule Program do@type t() :: [Operation.t()]@spec parse(binary) :: t()def parse(program_string) doprogram_string|> String.split("\n", trim: true)|> Enum.map(&Operation.parse/1)end@spec decorruptions(Program.t()) :: [Program.t()]def decorruptions(program) do[program | decorruptions([], program)]end@spec decorruptions(Program.t(), Program.t()) :: [Program.t()]def decorruptions(_, []) do[]enddef decorruptions(left, right) do[op | rest] = rightcase op do{:acc, _} -> decorruptions(left ++ [op], rest){:nop, n} -> [left ++ [{:jmp, n} | rest]] ++ decorruptions(left ++ [op], rest){:jmp, n} -> [left ++ [{:nop, n} | rest]] ++ decorruptions(left ++ [op], rest)endendend
defmodule Operation do@type t() :: {:nop, integer()} | {:acc, integer()} | {:jmp, integer()}@spec parse(binary()) :: Operation.t()def parse("nop " <> n) do{:nop, String.to_integer(n)}enddef parse("acc " <> n) do{:acc, String.to_integer(n)}enddef parse("jmp " <> n) do{:jmp, String.to_integer(n)}endend
defstruct ip: 0, acc: 0, program: [], visited: [], halt: false
defstruct ip: 0, acc: 0, program: [], visited: [], halt: false, eof: false@type t() :: %Machine{ip: integer(),acc: integer(),program: Program.t(),visited: [integer()],halt: boolean(),eof: boolean()}
if Enum.member?(machine.visited, machine.ip) do%Machine{machine | halt: true}elseoperation = machine.program |> Enum.at(machine.ip)machine |> Machine.apply(operation)
cond domachine.ip == length(machine.program) ->%Machine{machine | halt: true, eof: true}Enum.member?(machine.visited, machine.ip) ->%Machine{machine | halt: true}true ->operation = machine.program |> Enum.at(machine.ip)machine |> Machine.apply(operation)
def parse_operation("nop" <> _) do{:nop}enddef parse_operation("acc " <> n) do{:acc, String.to_integer(n)}enddef parse_operation("jmp " <> n) do{:jmp, String.to_integer(n)}enddef parse_program(program_string) doprogram_string |> String.split("\n", trim: true) |> Enum.map(&parse_operation/1)end
acc increases or decreases a single global value called the accumulator by the value given in the argument. For example, acc +7 would increase the accumulator by 7. The accumulator starts at 0. After an acc instruction, the instruction immediately below it is executed next.jmp jumps to a new instruction relative to itself. The next instruction to execute is found using the argument as an offset from the jmp instruction; for example, jmp +2 would skip the next instruction, jmp +1 would continue to the instruction immediately below it, and jmp -20 would cause the instruction 20 lines above to be executed next.nop stands for No OPeration - it does nothing. The instruction immediately below it is executed next.
**jmp** jumps to a new instruction relative to itself. The next instruction to execute is found using the argument as an offset from the jmp instruction; for example, jmp +2 would skip the next instruction, jmp +1 would continue to the instruction immediately below it, and jmp -20 would cause the instruction 20 lines above to be executed next.**nop** stands for No OPeration - it does nothing. The instruction immediately below it is executed next.
> left = [n0]>> right = [a1 j4, a3, j-3, a-99, a1, j-4, a6]>> out = [[n0, a1, j4, a3, j-3, a-99, a1, j-4, a6],>> [j0, a1, j4, a3, j-3, a-99, a1, j-4, a6]]