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

AoC 2023 - Day 01

2023/lang-elixir/01.livemd

AoC 2023 - Day 01

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

Part One

input_p1t =
  "day01-p1t.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()
input =
  "day01.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()
defmodule PartA do
  def solve(input) do
    input
    |> String.replace(~r/([A-Za-z])/, "")
    |> String.split("\n")
    |> Enum.map(&String.codepoints/1)
    |> Enum.map(&amp;(List.first(&amp;1) <> List.last(&amp;1)))
    |> Enum.map(&amp;String.to_integer/1)
    |> Enum.sum()
  end
end
PartA.solve(input_p1t)
PartA.solve(input)

Part Two

input_p2t =
  "day01-p2t.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()
defmodule PartB do
  @mapping %{
    "1" => 1,
    "2" => 2,
    "3" => 3,
    "4" => 4,
    "5" => 5,
    "6" => 6,
    "7" => 7,
    "8" => 8,
    "9" => 9,
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "four" => 4,
    "five" => 5,
    "six" => 6,
    "seven" => 7,
    "eight" => 8,
    "nine" => 9
  }

  def solve(input) do
    input
    |> String.split("\n")
    |> Enum.map(&amp;digit/1)
    |> Enum.map(&amp;(List.first(&amp;1) * 10 + List.last(&amp;1)))
    |> Enum.sum()
  end

  def solve_regex(input) do
    input
    |> String.split("\n")
    |> Enum.map(&amp;Regex.scan(~r/(?=(\d|one|two|three|four|five|six|seven|eight|nine))/, &amp;1))
    |> Enum.map(fn line ->
      [_discard, a] = List.first(line)
      [_discard, b] = List.last(line)

      Map.get(@mapping, a) * 10 + Map.get(@mapping, b)
    end)
    |> Enum.sum()
  end

  def solve_match(input) do
    input
    |> String.split("\n")
    |> Enum.map(&amp;digit_match/1)
    |> Enum.map(fn {x, y} -> x * 10 + y end)
    |> Enum.sum()
  end

  defp digit(input, acc \\ []) do
    case String.next_codepoint(input) do
      nil -> acc
      {_discard, string} -> digit(string, Enum.concat(acc, digit_mapping(input)))
    end
  end

  defp digit_match(input, acc \\ {0, 0}) do
    case String.next_codepoint(input) do
      nil -> acc
      {_discard, string} -> digit_match(string, digit_matcher(digit_mapping_match(input), acc))
    end
  end

  defp digit_matcher(nil, acc), do: acc
  defp digit_matcher(num, {0, 0}), do: {num, num}
  defp digit_matcher(num, {x, _y}), do: {x, num}

  defp digit_mapping(string) do
    for {digit, value} <- @mapping, String.starts_with?(string, digit) do
      value
    end
  end

  defp digit_mapping_match("1" <> _str), do: 1
  defp digit_mapping_match("2" <> _str), do: 2
  defp digit_mapping_match("3" <> _str), do: 3
  defp digit_mapping_match("4" <> _str), do: 4
  defp digit_mapping_match("5" <> _str), do: 5
  defp digit_mapping_match("6" <> _str), do: 6
  defp digit_mapping_match("7" <> _str), do: 7
  defp digit_mapping_match("8" <> _str), do: 8
  defp digit_mapping_match("9" <> _str), do: 9
  defp digit_mapping_match("one" <> _str), do: 1
  defp digit_mapping_match("two" <> _str), do: 2
  defp digit_mapping_match("three" <> _str), do: 3
  defp digit_mapping_match("four" <> _str), do: 4
  defp digit_mapping_match("five" <> _str), do: 5
  defp digit_mapping_match("six" <> _str), do: 6
  defp digit_mapping_match("seven" <> _str), do: 7
  defp digit_mapping_match("eight" <> _str), do: 8
  defp digit_mapping_match("nine" <> _str), do: 9
  defp digit_mapping_match(_str), do: nil
end
[PartB.solve(input_p2t), PartB.solve_regex(input_p2t), PartB.solve_match(input_p2t)]
[PartB.solve(input), PartB.solve_regex(input), PartB.solve_match(input)]