Skip to content

Commit 61a232a

Browse files
committed
working on day4
1 parent b2fb9e5 commit 61a232a

File tree

3 files changed

+1068
-0
lines changed

3 files changed

+1068
-0
lines changed

2016/day4/day4

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env escript
2+
%%! -sname day4
3+
4+
main([]) -> main(["input.txt"]);
5+
main([Filename]) ->
6+
compile:file("decoder.erl"),
7+
Rooms = load_input(Filename),
8+
io:format("Loaded ~p rooms~n", [length(Rooms)]),
9+
{ok, Pid} = decoder:start_link(),
10+
dispatch(Pid, Rooms),
11+
ok.
12+
13+
dispatch(_, []) -> ok;
14+
dispatch(Pid, [R | Rest]) ->
15+
decoder:add_room(Pid, R),
16+
dispatch(Pid, Rest).
17+
18+
load_input(Filename) ->
19+
{ok, File} = file:open(Filename, [read]),
20+
lists:reverse(load_input(File, [])).
21+
22+
load_input(File, List) ->
23+
case file:read_line(File) of
24+
{ok, Line} -> NewList = [ parse_line(Line) | List ],
25+
load_input(File, NewList);
26+
eof -> List
27+
end.
28+
29+
parse_line(Line) ->
30+
Tokens = string:tokens(Line, "-[]"),
31+
Segments = lists:sublist(Tokens, length(Tokens) - 3),
32+
[ SectorID, Checksum ] = lists:sublist(Tokens, length(Tokens) - 2, 2),
33+
{ Segments, SectorID, Checksum }.

2016/day4/decoder.erl

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
% Room Decoder Server
2+
3+
-module(decoder).
4+
-behavior(gen_server).
5+
-export([start_link/0,stop/1,add_room/2]).
6+
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
7+
8+
start_link() -> gen_server:start_link(?MODULE, [], []).
9+
10+
%% Calls
11+
add_room(Pid, Room) -> gen_server:cast(Pid, {add_room, Room}).
12+
stop(Pid) -> gen_server:call(Pid, stop).
13+
14+
%%% Server Functions
15+
init([]) -> {ok, []}.
16+
17+
handle_call(stop, _From, State) -> {stop, normal, ok, State};
18+
handle_call(Msg, _From, State) -> io:format("Unknown Message: ~p", [Msg]), {stop, unknown_message, State}.
19+
20+
handle_cast({add_room, Room}, State) ->
21+
% Determine if the room is a decoy
22+
{ActualChecksum, IsDecoy} = check_is_decoy(Room),
23+
RoomEntry = {Room, ActualChecksum, IsDecoy},
24+
io:format("Adding room to DB: ~p~n", [RoomEntry]),
25+
26+
% Store the room in the database
27+
{noreply, [ RoomEntry | State ]};
28+
handle_cast(Msg, State) -> io:format("Unknown Message: ~p", [Msg]), {stop, unknown_message, State}.
29+
30+
handle_info(Msg, State) -> io:format("Unknown Message: ~p", [Msg]), {stop, unknown_message, State}.
31+
32+
terminate(Reason, _State) ->
33+
io:format("Terminating ~p process because: ~p", ?MODULE, Reason),
34+
ok.
35+
36+
% We don't have any state migration.
37+
code_change(_OldVsn, State, _Extra) -> {ok, State}.
38+
39+
%% Private
40+
check_is_decoy({Segments, _, Checksum}) ->
41+
Letters = lists:sort(lists:flatten(Segments)),
42+
Groups = lists:foldr(fun(Elem, AccIn) ->
43+
case lists:keysearch(Elem, 1, AccIn) of
44+
false ->
45+
[ {Elem, 1} | AccIn];
46+
{value, {Letter, Count}} ->
47+
lists:keyreplace(Elem, 1, AccIn, {Letter, Count + 1})
48+
end
49+
end,
50+
[],
51+
Letters),
52+
Sorted = lists:reverse(lists:keysort(2, Groups)),
53+
Top5 = lists:sublist(Sorted, 1, 5),
54+
ActualChecksum = [ X || {X, _} <- Top5 ],
55+
{ActualChecksum, Checksum =/= ActualChecksum}.

0 commit comments

Comments
 (0)