127 lines
2.6 KiB
Elixir
127 lines
2.6 KiB
Elixir
|
|
defmodule Aoc19.Solution.Day04 do
|
||
|
|
@name "Day 4: Secure Container"
|
||
|
|
@behaviour Solution
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
def get_name, do: @name
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Get the range of numbers from the input.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.parse!("1-4")
|
||
|
|
1..4
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.parse!("4-32")
|
||
|
|
4..32
|
||
|
|
"""
|
||
|
|
def parse!(str) do
|
||
|
|
[start, stop] =
|
||
|
|
str
|
||
|
|
|> String.split("-")
|
||
|
|
|> Enum.map(&String.to_integer/1)
|
||
|
|
|
||
|
|
start..stop
|
||
|
|
end
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the first part of "Day 4: Secure Container".
|
||
|
|
"""
|
||
|
|
def solve_first_part(range),
|
||
|
|
do: range |> Stream.filter(&matches?/1) |> Enum.count()
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the second part of "Day 4: Secure Container".
|
||
|
|
"""
|
||
|
|
def solve_second_part(range),
|
||
|
|
do:
|
||
|
|
range
|
||
|
|
|> Stream.filter(&matches?/1)
|
||
|
|
|> Stream.filter(&larger_groups?/1)
|
||
|
|
|> Enum.count()
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Check if password matches all initital criterias.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(8)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(12)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(1123)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(22222)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(122345)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(111123)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(223450)
|
||
|
|
false
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.matches?(123789)
|
||
|
|
false
|
||
|
|
|
||
|
|
"""
|
||
|
|
def matches?(password) do
|
||
|
|
[a, b, c, d, e, f] = number_to_password(password) |> String.codepoints()
|
||
|
|
|
||
|
|
(a == b or b == c or c == d or d == e or e == f) and
|
||
|
|
(a <= b and b <= c and c <= d and d <= e and e <= f)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Check if password digit pairs are not part of a larget group of digits.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.larger_groups?(112233)
|
||
|
|
true
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.larger_groups?(123444)
|
||
|
|
false
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.larger_groups?(111122)
|
||
|
|
true
|
||
|
|
|
||
|
|
"""
|
||
|
|
def larger_groups?(password) do
|
||
|
|
washed = Regex.replace(~r/(\d)\1\1+/, number_to_password(password), "")
|
||
|
|
|
||
|
|
case Regex.run(~r/(\d)\1/, washed) do
|
||
|
|
nil -> false
|
||
|
|
_ -> true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Takes an integer and turns it to a password by making it a string
|
||
|
|
and left pad it with zeros.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.number_to_password(8)
|
||
|
|
"000008"
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.number_to_password(123)
|
||
|
|
"000123"
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day04.number_to_password(123123)
|
||
|
|
"123123"
|
||
|
|
|
||
|
|
"""
|
||
|
|
def number_to_password(n),
|
||
|
|
do: Integer.to_string(n) |> String.pad_leading(6, "0")
|
||
|
|
end
|