1
0
Fork 0
advent-of-code/2017/day18/day18.erl

175 lines
6.2 KiB
Erlang

-module(day18).
-export([start/0]).
value_or_register(X, Registers)
when X >= <<"a">>, X =< <<"z">> -> maps:get(X, Registers, 0);
value_or_register(X, _Registers)
-> { NewValue, _ } = string:to_integer(X),
NewValue.
assemble(Input)
-> Instructions = lists:map(fun(X) -> [A|Args] = re:split(X, " "), { A, Args } end, re:split(Input, "\n")),
assemble(Instructions, length(Instructions), 1, 0, maps:new()).
assemble(_Instructions, MaxInstructions, Ip, LastFrequency, _Registers)
when Ip < 1; Ip > MaxInstructions -> LastFrequency;
assemble(Instructions, MaxInstructions, Ip, LastFrequency, Registers)
-> { Op, Args } = lists:nth(Ip, Instructions),
case Op of
<<"add">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, maps:put(Src, ExistingValue + NewValue, Registers));
<<"jgz">> ->
[Src,Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
RegisterValue = maps:get(Src, Registers, 0),
if RegisterValue > 0 -> assemble(Instructions, MaxInstructions, Ip + NewValue, LastFrequency, Registers);
true -> assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, Registers)
end;
<<"mod">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, maps:put(Src, ExistingValue rem NewValue, Registers));
<<"mul">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, maps:put(Src, ExistingValue * NewValue, Registers));
<<"rcv">> ->
[Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
if NewValue /= 0 -> LastFrequency;
true -> assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, Registers)
end;
<<"set">> ->
[Src,Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
assemble(Instructions, MaxInstructions, Ip + 1, LastFrequency, maps:put(Src, NewValue, Registers));
<<"snd">> ->
[Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
assemble(Instructions, MaxInstructions, Ip + 1, NewValue, Registers)
end.
assemble2(Input)
-> Instructions = lists:map(fun(X) -> [A|Args] = re:split(X, " "), { A, Args } end, re:split(Input, "\n")),
assemble2(Instructions, length(Instructions), 1, maps:put(<<"p">>, 0, maps:new()), [], 0, 1, maps:put(<<"p">>, 1, maps:new()), []).
assemble2(Instructions, MaxInstructions, Ip0, Registers0, Queue0, SndCount, Ip1, Registers1, Queue1)
-> { NewIp0, NewRegisters0, NewQueue0, NewQueue1, _ } = assemble3(Instructions, MaxInstructions, Ip0, Registers0, Queue0, Queue1),
{ NewIp1, NewRegisters1, AnotherNewQueue1, AnotherNewQueue0, Count } = assemble3(Instructions, MaxInstructions, Ip1, Registers1, NewQueue1, NewQueue0),
NewSndCount = SndCount + Count,
%io:fwrite("newsndcount ~p~n", [NewSndCount]),
%io:fwrite("ip0 ~p ip1 ~p~nq0 ~p~nq1 ~p~n", [NewIp0, NewIp1, AnotherNewQueue0, AnotherNewQueue1]),
if Ip0 == NewIp0, Ip1 == NewIp1 -> NewSndCount;
true -> assemble2(Instructions, MaxInstructions, NewIp0, NewRegisters0, AnotherNewQueue0, NewSndCount, NewIp1, NewRegisters1, AnotherNewQueue1)
end.
assemble3(_Instructions, MaxInstructions, Ip, Registers, Queue, OtherQueue)
when Ip < 1; Ip > MaxInstructions -> { Ip, Registers, Queue, OtherQueue, 0 };
assemble3(Instructions, _MaxInstructions, Ip, Registers, Queue, OtherQueue)
-> { Op, Args } = lists:nth(Ip, Instructions),
case Op of
<<"add">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
{ Ip + 1, maps:put(Src, ExistingValue + NewValue, Registers), Queue, OtherQueue, 0 };
<<"jgz">> ->
[Src,Dest|_] = Args,
SrcValue = value_or_register(Src, Registers),
NewValue = value_or_register(Dest, Registers),
if SrcValue > 0 -> { Ip + NewValue, Registers, Queue, OtherQueue, 0 };
true -> { Ip + 1, Registers, Queue, OtherQueue, 0 }
end;
<<"mod">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
{ Ip + 1, maps:put(Src, (ExistingValue rem NewValue), Registers), Queue, OtherQueue, 0 };
<<"mul">> ->
[Src,Dest|_] = Args,
ExistingValue = maps:get(Src, Registers, 0),
NewValue = value_or_register(Dest, Registers),
{ Ip + 1, maps:put(Src, (ExistingValue * NewValue), Registers), Queue, OtherQueue, 0 };
<<"rcv">> ->
[Dest|_] = Args,
QueueLen = length(Queue),
if QueueLen == 0 -> { Ip, Registers, Queue, OtherQueue, 0 };
true -> [Head|Tail] = Queue, { Ip + 1, maps:put(Dest, Head, Registers), Tail, OtherQueue, 0 }
end;
<<"set">> ->
[Src,Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
{ Ip + 1, maps:put(Src, NewValue, Registers), Queue, OtherQueue, 0 };
<<"snd">> ->
[Dest|_] = Args,
NewValue = value_or_register(Dest, Registers),
{ Ip + 1, Registers, Queue, lists:append(OtherQueue, [NewValue]), 1 }
end.
start()
-> io:fwrite("~p~n", [ assemble("set a 1
add a 2
mul a a
mod a 5
snd a
set a 0
rcv a
jgz a -1
set a 1
jgz a -2") ]),
Instructions = "set i 31
set a 1
mul p 17
jgz p p
mul a 2
add i -1
jgz i -2
add a -1
set i 127
set p 952
mul p 8505
mod p a
mul p 129749
add p 12345
mod p a
set b p
mod b 10000
snd b
add i -1
jgz i -9
jgz a 3
rcv b
jgz b -1
set f 0
set i 126
rcv a
rcv b
set p a
mul p -1
add p b
jgz p 4
snd a
set a b
jgz 1 3
snd b
set f 1
add i -1
jgz i -11
snd a
jgz f -16
jgz a -19",
io:fwrite("~p~n", [ assemble(Instructions) ]),
io:fwrite("~p~n", [ assemble2("snd 1
snd 2
snd p
rcv a
rcv b
rcv c
rcv d") ]),
io:fwrite("~p~n", [ assemble2(Instructions) ]).