Last active
December 23, 2017 12:53
-
-
Save sasa1977/e5449390ae0cbeef2399222e32d8139f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Day23 do | |
defmodule Machine.Core do | |
def new(instructions), do: | |
%{ | |
registers: %{}, | |
position: 0, | |
instructions: instructions |> Enum.to_list() |> :array.from_list(fixed: true) | |
} | |
def done?(machine), do: | |
machine.position < 0 or machine.position >= :array.size(machine.instructions) | |
def current_instruction(machine), do: | |
:array.get(machine.position, machine.instructions) | |
def interpret(machine, {:set, [name, arg]}), do: | |
machine |> update_register(name, &%{&1 | value: value(machine, arg)}) |> next_instruction() | |
def interpret(machine, {:add, [name, arg]}), do: | |
machine |> update_register(name, &%{&1 | value: &1.value + value(machine, arg)}) |> next_instruction() | |
def interpret(machine, {:sub, [name, arg]}), do: | |
machine |> update_register(name, &%{&1 | value: &1.value - value(machine, arg)}) |> next_instruction() | |
def interpret(machine, {:mul, [name, arg]}), do: | |
machine |> update_register(name, &%{&1 | value: &1.value * value(machine, arg)}) |> next_instruction() | |
def interpret(machine, {:mod, [name, arg]}), do: | |
machine |> update_register(name, &%{&1 | value: rem(&1.value, value(machine, arg))}) |> next_instruction() | |
def interpret(machine, {:jgz, [x, y]}) do | |
if value(machine, x) > 0, do: jump(machine, value(machine, y)), else: next_instruction(machine) | |
end | |
def interpret(machine, {:jnz, [x, y]}) do | |
if value(machine, x) != 0, do: jump(machine, value(machine, y)), else: next_instruction(machine) | |
end | |
def update_register(machine, name, updater), do: | |
put_in(machine.registers[name], updater.(register(machine, name))) | |
def value(_machine, value) when is_integer(value), do: value | |
def value(machine, name) when is_binary(name), do: register(machine, name).value | |
def register(machine, name), do: Map.get(machine.registers, name, %{value: 0}) | |
def next_instruction(machine), do: jump(machine, 1) | |
defp jump(machine, offset), do: update_in(machine.position, &(&1 + offset)) | |
end | |
defmodule Machine.Part1 do | |
alias Day23.Machine | |
def new(instructions), do: | |
instructions |> Machine.Core.new() |> Map.merge(%{mul_count: 0}) | |
def done?(machine), do: Machine.Core.done?(machine) | |
def output(machine), do: machine.mul_count | |
def next(machine) do | |
{command, _} = instruction = Machine.Core.current_instruction(machine) | |
mul_count = if command == :mul, do: machine.mul_count + 1, else: machine.mul_count | |
Machine.Core.interpret(%{machine | mul_count: mul_count}, instruction) | |
end | |
end | |
def part1(), do: | |
run_machine(Day23.Machine.Part1) | |
def part2(), do: | |
0..1000 |> Stream.map(&(108_400 + &1 * 17)) |> Stream.reject(&prime?/1) |> Enum.count() | |
defp prime?(2), do: true | |
defp prime?(n) when n > 2, do: not Enum.any?(2..trunc(Float.ceil(:math.sqrt(n))), &rem(n, &1) == 0) | |
defp run_machine(machine_mod), do: | |
instructions() | |
|> machine_mod.new() | |
|> Stream.iterate(&machine_mod.next/1) | |
|> Stream.drop_while(&(not machine_mod.done?(&1))) | |
|> Enum.take(1) | |
|> hd() | |
|> machine_mod.output() | |
defp instructions(), do: | |
"input.txt" | |
|> File.stream!() | |
|> Stream.map(&String.trim/1) | |
|> Enum.map(&parse_instruction/1) | |
defp parse_instruction(instruction) do | |
[instruction | args] = String.split(instruction, " ") | |
{String.to_atom(instruction), Enum.map(args, &parse_arg/1)} | |
end | |
defp parse_arg(arg) do | |
case Integer.parse(arg) do | |
:error -> arg | |
{value, ""} -> value | |
end | |
end | |
end | |
Day23.part1() |> IO.inspect() | |
Day23.part2() |> IO.inspect() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment