aoc2024/src/day_2.erl

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.