Advent of Code 2020 - Day 2
AoC 2020 Day 2
Day 2 of the Advent of Code evaluates a string against a rule for validity.
Reading the input
read_input(File) ->
{'ok', Lines} = file:read_file(File),
[line_to_pw(Line) || Line <- binary:split(Lines, <<"\n">>, ['global']), Line =/= <<>>].
line_to_pw(Line) ->
{'match', [Min, Max, Char, PW]} = re:run(Line, <<"(\\d+)-(\\d+)\s+(\\w):\s+(.+)$">>, [{'capture', 'all_but_first', 'binary'}]),
{binary_to_integer(Min, 10), binary_to_integer(Max, 10), Char, PW}.
Here we utilize a regular expression to capture the Min and Max numbers (\d+
- 1 or more digits), the character the limits apply to (\w
- just one character), and the password to validate ((.+)
everything after the space until the end of the string).
Evaluating passwords
main(_) ->
PasswordDB = read_input("p2.txt"),
Valid = lists:foldl(fun count_valid_pw/2, 0, PasswordDB),
io:format('user', "valid: ~p~n", [Valid]).
count_valid_pw({Min, Max, Char, PW}, ValidCount) ->
case is_valid_pw(Min, Max, Char, PW) of
'true' -> ValidCount + 1;
'false' -> ValidCount
end.
is_valid_pw(Min, Max, Char, PW) ->
Count = length(binary:split(PW, Char, ['global']))-1,
Count >= Min andalso Count =< Max.
After loading the passwords and rules into PasswordDB
, we fold over the list and count only those passwords that are valid.
To validate the password, I chose to split the password on the Char
value, get the length of the list and decrement by one. For instance:
binary:split(<<"aaa">>, <<"a">>, ['global']).
[<<>>,<<>>,<<>>,<<>>]
Count = 3
binary:split(<<"cdefg">>, <<"b">>, ['global']).
[<<"cdefg">>]
Count = 0
binary:split(<<"ccccccccc">>, <<"c">>, ['global']).
[<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>]
Count = 9
Then it is a simple check on Min <= Count <= Max.
Part 2
The big change for part 2 is the is_valid_pw/4
function:
is_valid_pw(FirstPos, SecondPos, Char, PW) ->
case {char_at(FirstPos, PW), char_at(SecondPos, PW)} of
{Char, Char} -> 'false';
{Char, _} -> 'true';
{_, Char} -> 'true';
{_, _} -> 'false'
end.
char_at(Pos, PW) ->
erlang:binary_part(PW, Pos-1, 1).
Min and Max are re-interpreted as FirstPosition and SecondPosition. We get the character at each position and compare to Char. I explicitly show the truth table via pattern matching on Char but it is effectively an xor
operation. See for example:
33> (<<"c">> =:= <<"c">>) xor (<<"c">> =:= <<"c">>).
false
34> (<<"b">> =:= <<"c">>) xor (<<"c">> =:= <<"c">>).
true
35> (<<"c">> =:= <<"c">>) xor (<<"c">> =:= <<"b">>).
true
36> (<<"b">> =:= <<"c">>) xor (<<"c">> =:= <<"b">>).
false
Wrap-up
Not much trouble on this one. Getting the regexp right made the rest mostly took care of itself. Execution time for both parts remains ~0.180s.