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?

day05.livemd

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

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

Input

input = Kino.Input.textarea("Please paste your input:")
defmodule Day5Shared do
  def parse(input) do
    input
    |> Kino.Input.read()
    |> String.split("\n")
  end
end

Part 1

Santa needs help figuring out which strings in his text file are naughty or nice.

A nice string is one with all of the following properties:

  • It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
  • It contains at least one letter that appears twice in a row, like xx, abcdde (dd), or aabbccdd (aa, bb, cc, or dd).
  • It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other requirements.

For example:

  • ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter (...dd...), and none of the disallowed substrings.
  • aaa is nice because it has at least three vowels and a double letter, even though the letters used by different rules overlap.
  • jchzalrnumimnmhp is naughty because it has no double letter.
  • haegwjzuvuyypxyu is naughty because it contains the string xy.
  • dvszwmarrgswjxmb is naughty because it contains only one vowel.

How many strings are nice?

defmodule Day5Part1 do
  def classify(string),
    do: if(nice?(string), do: :nice, else: :naughty)

  defp nice?(string) do
    vowels = Regex.scan(~r/[aeiou]/, string)
    double_trouble = Regex.scan(~r/(.)\1/, string)
    naughty_pairs = Regex.scan(~r/ab|cd|pq|xy/, string)

    length(vowels) >= 3 and length(double_trouble) >= 1 and length(naughty_pairs) == 0
  end
end

input
|> Day5Shared.parse()
|> Enum.map(&Day5Part1.classify/1)
|> Enum.count(&(&1 == :nice))

Part 2

Realizing the error of his ways, Santa has switched to a better model of determining whether a string is naughty or nice. None of the old rules apply, as they are all clearly ridiculous.

Now, a nice string is one with all of the following properties:

  • It contains a pair of any two letters that appears at least twice in the string without overlapping, like xyxy (xy) or aabcdefgaa (aa), but not like aaa (aa, but it overlaps).
  • It contains at least one letter which repeats with exactly one letter between them, like xyx, abcdefeghi (efe), or even aaa.

For example:

  • qjhvhtzxzqqjkmpb is nice because is has a pair that appears twice (qj) and a letter that repeats with exactly one letter between them (zxz).
  • xxyxx is nice because it has a pair that appears twice and a letter that repeats with one between, even though the letters used by each rule overlap.
  • uurcxstgmygtbstg is naughty because it has a pair (tg) but no repeat with a single letter between them.
  • ieodomkazucvgmuy is naughty because it has a repeating letter with one between (odo), but no pair that appears twice.

How many strings are nice under these new rules?

defmodule Day5Part2 do
  def classify(string) do
    # again, let's use back-references, read more about back-references:
    # https://medium.com/rubycademy/3-ways-to-use-regexp-capture-groups-with-back-references-in-ruby-b4969cc9b3ec

    has_pairs? = Regex.match?(~r/([a-z][a-z]).*\1/, string)
    has_litms? = Regex.match?(~r/([a-z])[a-z]\1/, string)

    if has_pairs? and has_litms? do
      :nice
    else
      :naughty
    end
  end
end

input
|> Day5Shared.parse()
|> Enum.map(&Day5Part2.classify/1)
|> Enum.count(&(&1 == :nice))