Powered by AppSignal & Oban Pro

Day 1

notebooks/day01.livemd

Day 1

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

Puzzle

session = System.fetch_env!("LB_AOC_SESSION")

input =
  Req.get!(
    "https://adventofcode.com/2023/day/1/input",
    headers: [{"Cookie", ~s"session=#{session}"}]
  ).body

Kino.Text.new(input, terminal: true)

Part 1

calibration_value = fn line ->
  chars =
    line
    |> String.graphemes()

  {first, _} =
    chars
    |> Enum.find(&String.match?(&1, ~r/\d/))
    |> Integer.parse()

  {last, _} =
    chars
    |> Enum.reverse()
    |> Enum.find(&String.match?(&1, ~r/\d/))
    |> Integer.parse()

  Integer.undigits([first, last])
end
answer =
  input
  |> String.trim_trailing()
  |> String.splitter("\n")
  |> Enum.map(calibration_value)
  |> Enum.sum()

Part 2

to_digit = fn
  "zero" -> 0
  "one" -> 1
  "two" -> 2
  "three" -> 3
  "four" -> 4
  "five" -> 5
  "six" -> 6
  "seven" -> 7
  "eight" -> 8
  "nine" -> 9
  d -> Integer.parse(d) |> elem(0)
end

calibration_value = fn line ->
  matches =
    0..(String.length(line) - 1)
    |> Enum.map(
      &Regex.run(~r/\d|zero|one|two|three|four|five|six|seven|eight|nine/, line, offset: &1)
    )
    |> Enum.filter(&(!is_nil(&1)))
    |> Enum.flat_map(&Function.identity/1)

  first =
    List.first(matches)
    |> to_digit.()

  last =
    List.last(matches)
    |> to_digit.()

  Integer.undigits([first, last])
end
answer =
  input
  |> String.trim_trailing()
  |> String.splitter("\n")
  |> Enum.map(calibration_value)
  |> Enum.sum()