Advent of Code 2020 in Elixir - Day 2

Password Philosophy

defmodule Aoc2020.Day2 do
  @moduledoc "Password Philosophy"

  def parse_line(line) do
    String.split(line, [" ", "-", ":"])
    |> Enum.filter(&(&1 != ""))
    |> (fn [min, max, letter, password] ->
          [String.to_integer(min), String.to_integer(max), letter, password]
        end).()
  end

  def parse_input() do
    File.read!("priv/inputs/2020/day2.txt")
    |> String.trim()
    |> String.split("\n")
    |> Enum.map(&parse_line/1)
  end

  def occurrences_of_letter(letter, password) do
    String.codepoints(password)
    |> Enum.filter(&(&1 == letter))
    |> length
  end

  def check_letter_at_position(position, letter, password) do
    String.at(password, position - 1) == letter
  end

  # part 1
  def validate_policy([min, max, letter, password]) do
    occs = occurrences_of_letter(letter, password)
    occs >= min && occs <= max
  end

  # part 2
  def validate_policy_2([pos1, pos2, letter, password]) do
    [
      check_letter_at_position(pos1, letter, password),
      check_letter_at_position(pos2, letter, password)
    ]
    |> Enum.count(&(&1 == true))
    |> (fn count -> count == 1 end).()
  end

  def run do
    parse_input()
    |> Enum.filter(&validate_policy_2/1)
    |> length
  end
end