Skip to content

Instantly share code, notes, and snippets.

@ferd

ferd/day05.erl Secret

Created December 5, 2019 14:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ferd/a5c88c589df81d9e8754bac7e8457eba to your computer and use it in GitHub Desktop.
Save ferd/a5c88c589df81d9e8754bac7e8457eba to your computer and use it in GitHub Desktop.
%%% @doc
%%% fill this with the sorrows of the fifth challenge
%%% @end
-module(day05).
-export([p1/0, p2/0]).
-ifdef(TEST).
-export([extract_opcode/1, extract_param/2]).
-endif.
p1() ->
Src = str_to_source(advent:input("day05")),
run_program(0, source_to_map(Src)).
p2() ->
Src = str_to_source(advent:input("day05")),
run_program(0, source_to_map(Src)).
str_to_source(Str) ->
String = string:trim(Str),
[list_to_integer(S) || S <- string:lexemes(String, ",")].
run_program(P, Map) ->
{Op, ArgTypes} = instruction(maps:get(P, Map)),
Instr = {Op, get_args(P+1, ArgTypes, Map)},
case apply_instruction(Instr, Map, P) of
halt -> ok;
{NewMap, NewP} -> run_program(NewP, NewMap)
end.
apply_instruction({'+', [A,B,{addr,R}]}, Map, P) ->
{Map#{R := read_arg(A,Map) + read_arg(B, Map)},
P+4};
apply_instruction({'*', [A,B,{addr,R}]}, Map, P) ->
{Map#{R := read_arg(A,Map) * read_arg(B, Map)},
P+4};
apply_instruction({input, [{addr,R}]}, Map, P) ->
N = list_to_integer(string:trim(io:get_line("> "))),
{Map#{R := N}, P+2};
apply_instruction({output, [R]}, Map, P) ->
io:format("~p ", [read_arg(R, Map)]),
{Map, P+2};
apply_instruction({jmp_if_true, [Cond,R]}, Map, P) ->
case read_arg(Cond, Map) of
0 -> {Map, P+3};
_ -> {Map, read_arg(R, Map)}
end;
apply_instruction({jmp_if_false, [Cond,R]}, Map, P) ->
case read_arg(Cond, Map) of
0 -> {Map, read_arg(R, Map)};
_ -> {Map, P+3}
end;
apply_instruction({'<', [A,B,{addr,R}]}, Map, P) ->
Res = case read_arg(A, Map) < read_arg(B, Map) of
true -> 1;
false -> 0
end,
{Map#{R := Res}, P+4};
apply_instruction({'=:=', [A,B,{addr,R}]}, Map, P) ->
Res = case read_arg(A, Map) =:= read_arg(B, Map) of
true -> 1;
false -> 0
end,
{Map#{R := Res}, P+4};
apply_instruction({'exit', []}, _, _) ->
io:format("~n",[]),
halt.
read_arg({val, N}, _Map) ->
N;
read_arg({addr, N}, Map) ->
maps:get(N, Map).
get_args(_, [], _) -> [];
get_args(P, [H|T], Map) -> [{H, maps:get(P, Map)} | get_args(P+1, T, Map)].
instruction(N) ->
OpcodeDigit = extract_opcode(N),
{Op, ParamCount} = opcode(OpcodeDigit),
{Op, params_types(N, ParamCount)}.
params_types(N, ParamCount) -> params_types(N, 0, ParamCount).
params_types(_, C, C) ->
[];
params_types(N, C, ParamCount) ->
[extract_param(N, C+1) | params_types(N, C+1, ParamCount)].
opcode(1) -> {'+', 3};
opcode(2) -> {'*', 3};
opcode(3) -> {input, 1};
opcode(4) -> {output, 1};
opcode(5) -> {jmp_if_true, 2};
opcode(6) -> {jmp_if_false, 2};
opcode(7) -> {'<', 3};
opcode(8) -> {'=:=', 3};
opcode(99) -> {'exit', 0}.
extract_opcode(N) -> N rem 100.
extract_param(N, Nth) ->
Multiplier = pow(10, Nth),
Rem = 100 * Multiplier,
Div = 10 * Multiplier,
case (N rem Rem) div Div of
0 -> addr;
1 -> val
end.
pow(N, 1) -> N;
pow(N, M) -> pow(N*N, M-1).
source_to_map(Input) ->
{_, Map} = lists:foldl(
fun(N, {Index, Map}) -> {Index+1, Map#{Index => N}} end,
{0, #{}},
Input
),
Map.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment