Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 5: Doesn't He Have Intern-Elves For This?

2015/5.livemd

Day 5: Doesn’t He Have Intern-Elves For This?

Mix.install([
  {:kino, "~> 0.12.3"}
])

Modules

defmodule NiceStrings do
  @moduledoc """
  Functions for identifying nice strings.
  """

  @typedoc "The ruleset used to identify nice strings"
  @type rules :: :part1 | :part2

  @doc """
  Counts the number of strings that are "nice" according to a specified
  ruleset.

  ## Examples
  ```elixir
  iex> ["ugknbfddgicrmopn", "jchzalrnumimnmhp", "aaa"]
  iex> |> NiceStrings.count(:part1)
  2

  iex> ["qjhvhtzxzqqjkmpb", "ieodomkazucvgmuy", "uurcxstgmygtbstg"]
  iex> |> NiceStrings.count(:part2)
  1
  ```
  """
  @spec count(list(String.t()), rules()) :: non_neg_integer()
  def count(strings, rules) do
    strings
    |> Enum.count(&nice_string?(&1, rules))
  end

  # validates if string is nice
  defp nice_string?(str, rules)

  # using rules for part 1
  defp nice_string?(str, :part1) do
    contains_three_vowels?(str) and
      contains_double_letter?(str) and
      not contains_illegal_substring?(str)
  end

  # using rules for part 2
  defp nice_string?(str, :part2) do
    contains_pair_twice?(str) and
      contains_repeat_with_letter_between?(str)
  end

  # does the string have three vowels? using "a", "e", "i", "o" or "u"
  defp contains_three_vowels?(str), do: String.match?(str, ~r/(.*(a|e|i|o|u).*){3}/)

  # does the string contain a repeating letter consecutively? eg. "aa" or "pp"
  defp contains_double_letter?(str), do: String.match?(str, ~r/(\w)\1/)

  # does the string contain an illegal substring? "ab", "cd", "pq" or "xy"
  defp contains_illegal_substring?(str), do: String.match?(str, ~r/(ab|cd|pq|xy)/)

  # does the string contain the same pair of letters twice? eg. "rfaaiotaa" does
  defp contains_pair_twice?(str), do: String.match?(str, ~r/(\w\w).*(\1)/)

  # does the string contain a substring like "rtr" or "zxz" or "lgl"
  defp contains_repeat_with_letter_between?(str), do: String.match?(str, ~r/(\w)\w(\1)/)
end

Input

input = Kino.Input.textarea("Please paste your puzzle input:")

Part 1

input
|> Kino.Input.read()
|> String.split("\n")
|> NiceStrings.count(:part1)

Part 2

input
|> Kino.Input.read()
|> String.split("\n")
|> NiceStrings.count(:part2)