126 lines
3.4 KiB
Erlang
126 lines
3.4 KiB
Erlang
-module(day_2).
|
|
|
|
-export([part_1/0, part_2/0]).
|
|
|
|
part_1() ->
|
|
Filename = open_file(),
|
|
part_1(Filename).
|
|
|
|
part_1(Filename) ->
|
|
Reports = parse_input(Filename),
|
|
SafeReports = lists:filter(fun is_safe/1, Reports),
|
|
length(SafeReports).
|
|
|
|
part_2() ->
|
|
Filename = open_file(),
|
|
part_2(Filename).
|
|
|
|
part_2(Filename) ->
|
|
Reports = parse_input(Filename),
|
|
SafeReports = lists:filter(fun is_tolerably_safe/1, Reports),
|
|
length(SafeReports).
|
|
|
|
%% Private Functions
|
|
|
|
open_file() ->
|
|
Filename = filename:absname("./priv/input/2.txt"),
|
|
open_file(Filename).
|
|
|
|
open_file(Filename) ->
|
|
{ok, File} = file:open(Filename, read),
|
|
File.
|
|
|
|
parse_input(Filename) ->
|
|
parse_input(Filename, []).
|
|
|
|
parse_input(Filename, Reports) ->
|
|
case file:read_line(Filename) of
|
|
{ok, Line} ->
|
|
Trimmed = string:trim(Line),
|
|
Chunks = string:split(Trimmed, " ", all),
|
|
NonEmpty = lists:filter(fun(L) -> length(L) > 0 end, Chunks),
|
|
Report = lists:map(fun list_to_integer/1, NonEmpty),
|
|
parse_input(Filename, [Report | Reports]);
|
|
eof ->
|
|
Reports
|
|
end.
|
|
|
|
check_report([_Whatever | []]) ->
|
|
safe;
|
|
check_report([A | [B | _] = Rest]) when A < B andalso B - A < 4 ->
|
|
check_report(Rest, asc);
|
|
check_report([A | [B | _] = Rest]) when A > B andalso A - B < 4 ->
|
|
check_report(Rest, desc);
|
|
check_report(Rest) ->
|
|
unsafe.
|
|
|
|
check_report([_A], _Whatever) ->
|
|
safe;
|
|
check_report([A, B], asc) when A < B andalso B - A < 4 ->
|
|
safe;
|
|
check_report([A, B], desc) when A > B andalso A - B < 4 ->
|
|
safe;
|
|
check_report([A | [B | _] = Rest], asc) when A < B andalso B - A < 4 ->
|
|
check_report(Rest, asc);
|
|
check_report([A | [B | _] = Rest], desc) when A > B andalso A - B < 4 ->
|
|
check_report(Rest, desc);
|
|
check_report(_Rest, _Direction) ->
|
|
unsafe.
|
|
|
|
is_safe(Report) ->
|
|
safe == check_report(Report).
|
|
|
|
check_report_with_tolerance(Report) ->
|
|
case check_report(Report) of
|
|
safe ->
|
|
safe;
|
|
unsafe ->
|
|
check_report_by_removing_levels(Report)
|
|
end.
|
|
|
|
check_report_by_removing_levels([H | Tail]) ->
|
|
case check_report(Tail) of
|
|
safe -> safe;
|
|
unsafe ->
|
|
check_report_by_removing_levels([H], Tail)
|
|
end.
|
|
|
|
check_report_by_removing_levels(_Init, []) ->
|
|
unsafe;
|
|
check_report_by_removing_levels(Init, [H | Tail]) ->
|
|
case check_report(Init ++ Tail) of
|
|
safe ->
|
|
safe;
|
|
unsafe ->
|
|
check_report_by_removing_levels(Init ++ [H], Tail)
|
|
end.
|
|
|
|
|
|
is_tolerably_safe(Report) ->
|
|
safe == check_report_with_tolerance(Report).
|
|
|
|
-ifdef(TEST).
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
part_1_test() ->
|
|
TestFile = test_data(),
|
|
?assertEqual(2, part_1(TestFile)).
|
|
|
|
part_2_test() ->
|
|
TestFile = test_data(),
|
|
?assertEqual(4, part_2(TestFile)).
|
|
|
|
is_safe_4_test() -> ?assertEqual(safe, check_report([7, 6, 4, 2, 1])).
|
|
is_safe_5_test() -> ?assertEqual(unsafe, check_report([1, 2, 7, 8, 9])).
|
|
is_safe_6_test() -> ?assertEqual(unsafe, check_report([9, 7, 6, 2, 1])).
|
|
is_safe_7_test() -> ?assertEqual(unsafe, check_report([1, 3, 2, 4, 5])).
|
|
is_safe_8_test() -> ?assertEqual(unsafe, check_report([8, 6, 4, 4, 1])).
|
|
is_safe_9_test() -> ?assertEqual(safe, check_report([1, 3, 6, 7, 9])).
|
|
is_safe_10_test() -> ?assertEqual(safe, check_report([40, 42, 44, 46, 49, 51])).
|
|
|
|
|
|
test_data() ->
|
|
open_file("./priv/test_input/2.txt").
|
|
|
|
-endif.
|