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

Day 1

day01.livemd

Day 1

Section

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

Data

input = Kino.Input.textarea("Please paste your input file:")

Solutions

Part 1

Example data:

1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

In this example, the calibration values of these four lines are 12, 38, 15, and 77. Adding these together produces 142.

input = Kino.Input.read(input)

defmodule Advent2023.Day01.Part1 do
  @text_digits Enum.map(0..9, &{Integer.to_string(&1), &1}) |> Enum.into(%{})

  def get_first_and_last_digit(text) do
    text
    |> String.split("", trim: true)
    |> Enum.reduce({nil, 0}, &process_character/2)
  end

  def process_character(character, {nil, last}) do
    maybe_digit = @text_digits[character]
    if maybe_digit, do: {maybe_digit, maybe_digit}, else: {nil, last}
  end

  def process_character(character, {first, last}) do
    maybe_digit = @text_digits[character]
    if maybe_digit, do: {first, maybe_digit}, else: {first, last}
  end

  def add({nil, last}), do: last
  def add({first, last}), do: first * 10 + last

  def single_calibration(calibration) do
    calibration
    |> get_first_and_last_digit()
    |> add()
  end

  def multiple_calibrations(calibration_list) do
    calibration_list
    |> Enum.reduce(0, fn sum, acc -> single_calibration(sum) + acc end)
  end
end

input
|> String.splitter("\n", trim: true)
|> Advent2023.Day01.Part1.multiple_calibrations()

Part 2

Example:

two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen

In this example, the calibration values are 29, 83, 13, 24, 42, 14, and 76. Adding these together produces 281.

defmodule Advent2023.Day01.Part2 do
  @number_lookup %{
    "one" => "1",
    "two" => "2",
    "three" => "3",
    "four" => "4",
    "five" => "5",
    "six" => "6",
    "seven" => "7",
    "eight" => "8",
    "nine" => "9",
    "zero" => "0"
  }
  @text_digits Enum.map(0..9, &{Integer.to_string(&1), &1}) |> Enum.into(%{})

  def get_matched_numbers(text) do
    list_of_all_digits = Map.keys(@number_lookup) ++ Map.values(@number_lookup)
    pattern = ~r/(?=(#{Enum.join(list_of_all_digits, "|")}))/i
    Regex.scan(pattern, text)
  end

  def get_first_and_last_digit([]), do: {0, 0}

  def get_first_and_last_digit(list) do
    [_, first] = List.first(list)
    [_, last] = List.last(list)
    {numberize(first), numberize(last)}
  end

  def numberize(number_string) do
    Map.get(@number_lookup, number_string, number_string)
    |> String.to_integer()
  end

  def add({first, last}), do: first * 10 + last

  def single_calibration(calibration) do
    calibration
    |> get_matched_numbers()
    |> get_first_and_last_digit()
    |> add()
  end

  def multiple_calibrations(calibration_list) do
    calibration_list
    |> Enum.reduce(0, fn sum, acc -> single_calibration(sum) + acc end)
  end
end

# Advent2023.Day01.Part2.single_calibration("eightwothree")

input
|> String.splitter("\n", trim: true)
|> Advent2023.Day01.Part2.multiple_calibrations()