diff --git a/day18/Makefile b/day18/Makefile new file mode 100644 index 0000000..75fcd48 --- /dev/null +++ b/day18/Makefile @@ -0,0 +1,8 @@ +all: day18.beam + erl -noshell -s day18 start -s init stop + +day18.beam: + erlc day18.erl + +clean: + rm -f day18.beam diff --git a/day18/day18.erl b/day18/day18.erl new file mode 100644 index 0000000..746ff1b --- /dev/null +++ b/day18/day18.erl @@ -0,0 +1,174 @@ +-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) ]).