advent-of-code/2019-elixir/lib/solutions/day_04.ex
2021-11-01 16:45:03 +01:00

126 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