-
Notifications
You must be signed in to change notification settings - Fork 0
/
sol08b.erl
executable file
·89 lines (73 loc) · 2.12 KB
/
sol08b.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/escript
-record(i, {op :: atom(),
param :: integer(),
anno :: map()
}).
-record(state, {acc :: integer(),
pc :: integer(),
return :: halt | break
}).
main([]) ->
main(["sol08.data"]);
main([Filename]) ->
{ok, File} = file:open(Filename, [read, binary]),
Code = compile(File),
file:close(File),
ChangePoints =
lists:filter(
fun ({_, #i{op=Op}}) -> (Op =:= nop) or (Op =:= jmp) end,
maps:to_list(Code)),
Results = [try_change_exec(Code, CP) || CP <- ChangePoints],
Terminations =
lists:filter(
fun (#state{return=R}) -> R =:= halt end,
Results),
[#state{acc=Acc}] = Terminations,
io:format("~B~n", [Acc]).
compile(File) ->
compile(File, 0, #{}).
compile(File, LineNo, Ins) ->
case file:read_line(File) of
eof ->
Ins;
{ok, Line} ->
NewIns = Ins#{LineNo => compile_line(string:chomp(Line))},
compile(File, LineNo+1, NewIns)
end.
compile_line(<<Ins:3/binary, " ", Sgn:1/binary, Value/binary>>) ->
#i{op=map_instruction(Ins), param=map_param(Sgn, Value), anno=#{reps=>0}}.
map_instruction(Ins) ->
binary_to_atom(Ins).
map_param(<<"-">>, Value) ->
-binary_to_integer(Value);
map_param(<<"+">>, Value) ->
binary_to_integer(Value).
exec(Code, #state{pc=PC} = State) ->
Instr = maps:get(PC, Code, #i{anno=#{halt => 1}}),
#i{op=Op, param=Param, anno=Anno} = Instr,
case Anno of
#{halt:=_} ->
State#state{return=halt};
#{reps:=N} when N < 1 ->
NewState = exec_instruction(Op, Param, State),
NewAnno = Anno#{reps => N+1},
NewInstr = Instr#i{anno=NewAnno},
NewCode = Code#{PC => NewInstr},
exec(NewCode, NewState);
#{reps:=N} when N >= 1 ->
State#state{return=break}
end.
exec_instruction(nop, _, #state{pc=PC} = State) ->
State#state{pc=PC+1};
exec_instruction(acc, N, #state{acc=Acc, pc=PC} = State) ->
State#state{acc=Acc+N, pc=PC+1};
exec_instruction(jmp, N, #state{pc=PC} = State) ->
State#state{pc=PC+N}.
try_change_exec(Code, {L, Ins}) ->
NewIns = case Ins of
#i{op=jmp} -> Ins#i{op=nop};
#i{op=nop} -> Ins#i{op=jmp}
end,
io:format("Changing ~p to ~p~n", [Ins, NewIns]),
State = #state{acc=0, pc=0},
exec(Code#{L => NewIns}, State).