2V5JBKFOQ7U4WQQ4KFO67OJCS3MUSRGJN5656IULIJSUIJL7TCUQC ExUnit.start()
defmodule HandheldHaltingTest douse ExUnit.Casedoctest HandheldHaltingtest "new machine has ip 0" doassert Machine.init().ip == 0endtest "new machine has acc 0" doassert Machine.init().acc == 0endtest "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_programendtest "visited instructions" domachine = Machine.init()assert machine.visited == []machine_2 = machine |> Machine.apply({:nop})assert machine_2.visited == [0]machine_3 = machine_2 |> Machine.apply({:nop})assert machine_3.visited == [1, 0]endtest "stepping through program" domachine = [{:nop}, {:acc, 4}, {:acc, -10}] |> Machine.init()assert machine.ip == 0assert machine.acc == 0assert machine.visited == []machine = machine |> Machine.step()assert machine.ip == 1assert machine.acc == 0assert machine.visited == [0]machine = machine |> Machine.step()assert machine.ip == 2assert machine.acc == 4assert machine.visited == [1, 0]machine = machine |> Machine.step()assert machine.ip == 3assert machine.acc == -6assert machine.visited == [2, 1, 0]endtest "halt when reveisiting instruction" domachine = [{:nop}, {:acc, 4}, {:jmp, -1}, {:acc, 9}] |> Machine.init()assert machine.ip == 0assert machine.acc == 0assert machine.visited == []assert machine.halt == falsemachine = machine |> Machine.step()assert machine.ip == 1assert machine.acc == 0assert machine.visited == [0]assert machine.halt == falsemachine = machine |> Machine.step()assert machine.ip == 2assert machine.acc == 4assert machine.visited == [1, 0]assert machine.halt == falsemachine = machine |> Machine.step()assert machine.ip == 1assert machine.acc == 4assert machine.visited == [2, 1, 0]assert machine.halt == falsemachine = machine |> Machine.step()assert machine.ip == 1assert machine.acc == 4assert machine.visited == [2, 1, 0]assert machine.halt == trueendtest "run program" domachine = [{:nop}, {:acc, 4}, {:jmp, -1}, {:acc, 9}] |> Machine.init() |> Machine.run()assert machine.ip == 1assert machine.acc == 4assert machine.visited == [2, 1, 0]assert machine.halt == trueendtest "part 1" domachine = File.read!("input") |> HandheldHalting.parse_program() |> Machine.init()halted = machine |> Machine.run()IO.inspect(halted.acc, label: "Part 1")endend
%{"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},"mix_test_watch": {:hex, :mix_test_watch, "1.0.2", "34900184cbbbc6b6ed616ed3a8ea9b791f9fd2088419352a6d3200525637f785", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "47ac558d8b06f684773972c6d04fcc15590abdb97aeb7666da19fcbfdc441a07"},}
defmodule HandheldHalting.MixProject douse Mix.Projectdef project do[app: :handheld_halting,version: "0.1.0",elixir: "~> 1.10",start_permanent: Mix.env() == :prod,deps: deps()]end# Run "mix help compile.app" to learn about applications.def application do[extra_applications: [:logger]]end# Run "mix help deps" to learn about dependencies.defp deps do[{:mix_test_watch, "~> 1.0", only: :dev, runtime: false}]endend
defmodule Machine dodefstruct ip: 0, acc: 0, program: [], visited: [], halt: falsedef init() do%Machine{}enddef init(program) do%Machine{program: program}enddef apply(%Machine{} = machine, {:nop}) do%Machine{machine | ip: machine.ip + 1, visited: [machine.ip | machine.visited]}enddef apply(%Machine{} = machine, {:acc, n}) when is_integer(n) do%Machine{machine| ip: machine.ip + 1,acc: machine.acc + n,visited: [machine.ip | machine.visited]}enddef apply(%Machine{} = machine, {:jmp, n}) when is_integer(n) do%Machine{machine | ip: machine.ip + n, visited: [machine.ip | machine.visited]}enddef step(%Machine{} = machine) doif Enum.member?(machine.visited, machine.ip) do%Machine{machine | halt: true}elseoperation = machine.program |> Enum.at(machine.ip)machine |> Machine.apply(operation)endenddef run(%Machine{} = machine) domachine |> inner_run()enddefp inner_run(machine) doif(machine.halt) domachineelsemachine |> step() |> inner_runendendend
defmodule HandheldHalting dodef 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)endend
jmp +1acc -18acc +19acc +19jmp +202acc +15acc +42acc +30acc -7jmp +535acc +31acc +9jmp +581nop +501acc +44acc +18acc -4jmp +545acc +9acc +5nop -2acc +3jmp +475acc -10acc +14acc +29nop +471jmp +470acc +2nop +375acc +31acc +6jmp +420acc -1acc +2nop +185jmp +490acc +2jmp +317nop +282jmp +457acc +37jmp +254acc +19jmp +436jmp +458acc -7acc -2acc -17jmp +454acc +37jmp +212acc +6acc +5acc -7jmp +104acc +5nop +134acc +46jmp +541acc +4acc +46acc +18jmp -53acc +10jmp +285acc +39acc +34nop +109acc +47jmp +32jmp +1jmp +143acc +36jmp +429acc +45acc +22jmp -59acc +0acc +23acc +30acc -7jmp -45acc +46acc +31jmp +164acc +37acc +34acc +40acc -1jmp +246nop -46acc +2acc +31jmp +221nop +413jmp -51acc -14jmp +145acc +1nop +77jmp +131jmp +370nop +513acc +7jmp +476acc +22acc +37acc +44jmp +334acc +9acc -1acc +5acc +27jmp +351acc +31jmp +220nop -61acc +34jmp +504nop +471acc +6acc +48jmp -17jmp +217acc +13acc +0acc +25jmp +144acc -5acc +17nop +341jmp -26acc -10acc +34jmp +168nop -16acc -6acc -10acc +38jmp +30acc -2acc -14jmp +419acc +40acc -17acc +27acc +8jmp +101nop +370acc +2acc -10acc -7jmp +224nop +437acc +42acc +50acc +39jmp +81jmp +11jmp +143acc +6acc +46jmp -107acc +13jmp -109acc +5jmp +1jmp +467jmp -159nop +421jmp +243acc +44nop +412acc -6acc +13jmp +56acc -12acc +18jmp +313nop +151acc +5acc +49jmp +120acc +46acc +23nop -122acc +21jmp -55acc -15jmp -115acc +19nop +116acc +32acc +21jmp +16acc +27acc +32jmp +359acc +16acc +18acc +15jmp +54nop +182acc +4jmp +361acc +4acc +38acc +49jmp -94jmp +428acc +0acc +9jmp +224jmp +82nop +57acc +6jmp +1jmp +144jmp +20jmp +265jmp +402nop +114acc -12acc -11acc +1jmp +412nop -163acc +50acc +1acc -9jmp -20acc +10acc +6jmp +323acc +10jmp +1acc +42jmp +46acc +35acc +31jmp -139jmp +129jmp -193acc -4nop +247nop -163acc +25jmp -26acc +34acc +26acc +40jmp +220acc -6acc +6jmp +311acc +0acc +14acc +41acc +6jmp +284acc +32jmp -13nop +157acc -4acc +47jmp -146acc +34acc +6nop +196acc +5jmp +268acc -8jmp -176acc +34acc +17jmp +1jmp +114acc +32acc +39nop +313acc +38jmp -237jmp -273acc +21acc +26acc +31jmp -231acc +17jmp -105nop +333nop +17jmp +11acc -9acc +2jmp -162acc +3acc +0nop +318jmp +215acc +14acc +32jmp -196jmp +33acc -6acc +45acc +27jmp -166acc -1jmp -25acc +0acc +4acc -14acc +0jmp -115nop +118acc +28nop +175acc +45jmp -97jmp +78jmp -284acc +35nop -248acc -18acc -6jmp -308jmp -95acc -2acc +0jmp +255acc +7jmp -24acc +17acc +20jmp -220jmp +172acc +40acc +39acc +19jmp -238nop +44nop -99nop +238jmp +195acc -14acc +36acc +40acc -11jmp -65nop -54nop +47acc -11jmp +18jmp +98jmp +252nop -1acc +1acc +10jmp -4jmp -319jmp -46acc -8acc +50acc +43jmp -174acc +22acc +4acc +32acc -6jmp +73acc +8jmp -31acc +16nop +11acc +26jmp -98acc -11acc +40jmp +101acc +28acc +30acc -16acc +7jmp +239jmp -179acc +47acc +15acc +42acc +26jmp +30acc +17acc +3acc -5nop -98jmp -236acc +2jmp +196acc +39acc -14acc +36acc +49jmp +189jmp +235acc +27acc -2acc +16acc +40jmp -81acc -5acc +17acc -1jmp +1jmp -129nop -171acc +47jmp +169acc -16acc -5jmp +172nop -84acc +8acc +40acc +43jmp -33acc +39nop -12jmp +53acc +36jmp -270acc +17acc -1jmp -255acc +0acc -12jmp -371jmp -216acc +45acc -18acc +23acc -17jmp -37jmp -386nop -302acc -19acc -16jmp -297acc -18acc -7acc +17acc +17jmp -173jmp +114acc +4acc +19nop -296jmp -36acc -18acc -14acc +6nop -27jmp -101acc +15nop -407jmp +44acc -18acc -6acc +33acc +36jmp +80acc +43jmp +73acc -2acc +7acc +4jmp -10acc +46nop -49acc +7jmp +65acc +24jmp +144acc +13acc +26jmp -351jmp +1acc +34nop +62jmp -363acc -4acc -5jmp +23jmp +82acc -7acc -7acc +15jmp -468acc +7nop -423jmp -178nop -425acc +23jmp -181acc +6acc -11jmp -321acc +3jmp -122acc +12jmp +44acc -5acc -16acc +16jmp -281acc +33acc -4acc +15jmp +9jmp +63acc +35nop -12acc +25acc -10jmp -452acc +1jmp -148acc +8acc +40acc +48jmp +2jmp -315nop -325acc -4acc +16acc -4jmp -369acc +21acc +3jmp -153nop -25acc +0jmp -84acc +32jmp +19acc -18acc -1jmp -385jmp +1jmp -357acc -13acc -13jmp -360jmp -393acc +4nop -102jmp -316jmp -248acc +4nop -487jmp -339acc +3jmp -190acc +24acc +31jmp -166jmp -482acc +22acc +32jmp -290acc +22acc +48acc +5acc -6jmp -330nop -203acc +7acc +1jmp -287acc +15acc +3jmp -230acc +37nop -162jmp +33jmp -147acc +16acc +39acc +49jmp -560acc +26jmp +26jmp -283jmp -486acc -9jmp +1acc +25acc +1jmp -514acc +46jmp -166acc -5acc +35nop -204jmp -175nop -30nop +11jmp -400acc +15acc -7acc -1jmp +18acc +31acc +16acc +43acc +33jmp -260acc +1acc +23acc +25acc -1jmp -200acc -15jmp -314jmp -238jmp -75jmp -192acc +30jmp -525acc -14jmp +17acc +7acc +9acc -6nop -312jmp -559acc +28jmp -305jmp -239acc +0acc -5acc +9jmp -471nop -327acc -5acc -19jmp -496acc +17jmp +1jmp +1acc +29jmp +1
nop +0acc +1jmp +4acc +3jmp -3acc -99acc +1jmp -4acc +6
--- Day 8: Handheld Halting ---Your flight to the major airline hub reaches cruising altitude without incident. While you consider checking the in-flight menu for one of those drinks that come with a little umbrella, you are interrupted by the kid sitting next to you.Their handheld game console won't turn on! They ask if you can take a look.You narrow the problem down to a strange infinite loop in the boot code (your puzzle input) of the device. You should be able to fix it, but first you need to be able to run the code in isolation.The boot code is represented as a text file with one instruction per line of text. Each instruction consists of an operation (acc, jmp, or nop) and an argument (a signed number like +4 or -20).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.For example, consider the following program:nop +0acc +1jmp +4acc +3jmp -3acc -99acc +1jmp -4acc +6These instructions are visited in this order:nop +0 | 1acc +1 | 2, 8(!)jmp +4 | 3acc +3 | 6jmp -3 | 7acc -99 |acc +1 | 4jmp -4 | 5acc +6 |First, the nop +0 does nothing. Then, the accumulator is increased from 0 to 1 (acc +1) and jmp +4 sets the next instruction to the other acc +1 near the bottom. After it increases the accumulator from 1 to 2, jmp -4 executes, setting the next instruction to the only acc +3. It sets the accumulator to 5, and jmp -3 causes the program to continue back at the first acc +1.This is an infinite loop: with this sequence of jumps, the program will run forever. The moment the program tries to run any instruction a second time, you know it will never terminate.Immediately before the program would run an instruction a second time, the value in the accumulator is 5.Run your copy of the boot code. Immediately before any instruction is executed a second time, what value is in the accumulator?--- Part Two ---After some careful analysis, you believe that exactly one instruction is corrupted.Somewhere in the program, either a jmp is supposed to be a nop, or a nop is supposed to be a jmp. (No acc instructions were harmed in the corruption of this boot code.)The program is supposed to terminate by attempting to execute an instruction immediately after the last instruction in the file. By changing exactly one jmp or nop, you can repair the boot code and make it terminate correctly.For example, consider the same program from above:nop +0acc +1jmp +4acc +3jmp -3acc -99acc +1jmp -4acc +6If you change the first instruction from nop +0 to jmp +0, it would create a single-instruction infinite loop, never leaving that instruction. If you change almost any of the jmp instructions, the program will still eventually find another jmp instruction and loop forever.However, if you change the second-to-last instruction (from jmp -4 to nop -4), the program terminates! The instructions are visited in this order:nop +0 | 1acc +1 | 2jmp +4 | 3acc +3 |jmp -3 |acc -99 |acc +1 | 4nop -4 | 5acc +6 | 6After the last instruction (acc +6), the program terminates by attempting to run the instruction below the last instruction in the file. With this change, after the program terminates, the accumulator contains the value 8 (acc +1, acc +1, acc +6).Fix the program so that it terminates normally by changing exactly one jmp (to nop) or nop (to jmp). What is the value of the accumulator after the program terminates?
# HandheldHalting**TODO: Add description**## InstallationIf [available in Hex](https://hex.pm/docs/publish), the package can be installedby adding `handheld_halting` to your list of dependencies in `mix.exs`:```elixirdef deps do[{:handheld_halting, "~> 0.1.0"}]end```Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)and published on [HexDocs](https://hexdocs.pm). Once published, the docs canbe found at [https://hexdocs.pm/handheld_halting](https://hexdocs.pm/handheld_halting).