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

day4

2020-Elixir/day4.livemd

day4

Mix.install([:kino])

Section

input = Kino.Input.textarea("input file: ")
input = Kino.Input.read(input)

defmodule Valid do
  def all_fields_valid?(record) do
    Enum.all?(record, fn {field, value} -> valid?(field, value) end)
  end

  def valid?(field, year) when field in ["byr", "eyr", "iyr"] and is_binary(year) do
    valid?(field, String.to_integer(year))
  end

  def valid?("byr", year) when year in 1920..2002, do: true
  def valid?("iyr", year) when year in 2010..2020, do: true
  def valid?("eyr", year) when year in 2020..2030, do: true

  def valid?("hgt", {cm, "cm"}) when cm in 150..193, do: true
  def valid?("hgt", {inch, "in"}) when inch in 59..76, do: true
  def valid?("hgt", {_, _}), do: false
  def valid?("hgt", height), do: valid?("hgt", Integer.parse(height))

  def valid?("hcl", color), do: Regex.match?(~r/^#[0-9a-f]{6}$/, color)
  def valid?("pid", pid), do: Regex.match?(~r/^[0-9]{9}$/, pid)

  def valid?("ecl", color) when color in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"],
    do: true

  def valid?("cid", _), do: true
  def valid?(_, _), do: false

  def all_fields_present?(record) do
    Map.keys(record)
    |> MapSet.new()
    |> subset?()
  end

  def subset?(set) do
    needs = MapSet.new(["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"])
    MapSet.subset?(needs, set)
  end
end

data =
  input
  |> String.split("\n\n")
  |> Enum.map(
    &(String.split(&1, [" ", "\n", ":"])
      |> Enum.chunk_every(2)
      |> Map.new(fn [k, v] -> {k, v} end))
  )

part1 =
  data
  |> Enum.count(&Valid.all_fields_present?(&1))
  |> IO.puts()

part2 =
  data
  |> Enum.count(&(Valid.all_fields_valid?(&1) and Valid.all_fields_present?(&1)))
  |> IO.puts()