This one didn’t seem too bad, but I can’t help but feel there’s a “clever” solution that alludes me. Some sort of funky math theorizing that I just don’t know about.
Puzzle 1
Put on your hacker gloves, it’s time to crack some passwords!
Oh, you only want a count of possible ones? That shouldn’t be too hard.
First, a function to check if the digits/2
of the password match the rules.
def p1_possible(y) do
length(y) == 6 and Enum.sort(y) == y and check_doubles(y)
end
While I feel like there should be some fancy way to check if doubles exist, I
decided chunk_every/4
would work great here.
defp check_doubles(y) do
y
|> Enum.chunk_every(2, 1, :discard)
|> Enum.any?(fn [a, b] -> a == b end)
end
Similar to yesterday’s puzzle, I am taking two adjacent digits and making sure they are equal. All that’s left is to count up the good ones.
def compute_possibles([s, e]) do
Enum.reduce(s..e, 0, fn x, acc ->
y = Integer.digits(x)
if p1_possible(y) do
acc + 1
else
acc
end
end)
end
Boom, HACKED
Puzzle 2
Puzzle 2 has a nice little spin on the original problem, declaring that there is definitely at least one set of just doubles in the password.
111111
is no good, as there isn’t a set of doubles all on its own111122
is good, because the22
is a double.
I can already re-use p1_possible/1
, as all of those rules apply as well. To see
if there is a unique set of doubles, I can use chunk_while/4
to only emit
chunks when the current digit is different than the last one.
defp check_unique_doubles(y) do
y
|> Enum.chunk_while(
[],
fn
x, [] -> {:cont, [x]}
x, [x | _t] = acc -> {:cont, [x | acc]}
x, [_y | _t] = acc -> {:cont, acc, [x]}
end,
fn x -> {:cont, x, []} end
)
|> Enum.any?(fn x -> length(x) == 2 end)
end
I also decided it would be easiest to use pattern matching in the anonymous
function, to avoid any extra if
s or cond
s. I’m not really sure what the last
parameter is for, titled after_fun
. It says that it runs after iteration is
done, but I don’t understand what the difference is between returning {:cont,
element, acc}
and {:cont, acc}
is. Something to look into at a later time!
After that, I just need to check if any chunk has a length of 2.
The solution is the same as before, but with the new p2_possible/1
instead.
def compute_possibles([s, e]) do
Enum.reduce(s..e, 0, fn x, acc ->
y = Integer.digits(x)
if p2_possible(y) do
acc + 1
else
acc
end
end)
end
def p2_possible(y) do
p1_possible(y) and check_unique_doubles(y)
end
Calculating… calculating… .20 seconds is pretty quick still! I’m pleasantly surprised. received.
Conclusion
I, uh, actually didn’t write any tests for this one. It was pretty straight-forward and I manged to solve each puzzle on the first try, which is always nice. I can’t help but think that there’s a better way to do this than brute-forcing things, but, hey, it finished really quick.
That’s all today! On to day 5!