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

AoC 2023 - Day 3

2023/day03.livemd

AoC 2023 - Day 3

Mix.install([:kino])

Section

input = Kino.Input.textarea("enter input")

Common

defmodule AoC.Day3 do
end

Part 1

lines_with_index =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.with_index()

nums_with_positions =
  lines_with_index
  |> Enum.flat_map(fn {line, i} ->
    Regex.scan(~r/\d+/, line, return: :index)
    |> List.flatten()
    |> Enum.map(fn {j, len} ->
      {(i - 1)..(i + 1)//1, (j - 1)..(j + len)//1, String.to_integer(String.slice(line, j, len))}
    end)
  end)

symbol_positions =
  lines_with_index
  |> Stream.flat_map(fn {line, i} ->
    Regex.scan(~r/[^a-zA-Z0-9\.]/, line, return: :index)
    |> List.flatten()
    |> Enum.map(fn {j, _} -> {i, j} end)
  end)
  |> MapSet.new()

nums_with_positions
|> Stream.filter(fn {row_span, col_span, _n} ->
  for i <- row_span,
      j <- col_span,
      reduce: false,
      do: (acc -> acc || {i, j} in symbol_positions)
end)
|> Stream.map(&amp;elem(&amp;1, 2))
|> Enum.sum()

Part 2

lines_with_index
|> Stream.flat_map(fn {line, i} ->
  Regex.scan(~r/\*/, line, return: :index)
  |> List.flatten()
  |> Enum.map(fn {j, _} -> {i, j} end)
end)
|> Stream.map(fn {i, j} ->
  case Enum.filter(nums_with_positions, fn {row_span, col_span, _n} ->
         i in row_span and j in col_span
       end) do
    [a, b] -> elem(a, 2) * elem(b, 2)
    _ -> 0
  end
end)
|> Enum.sum()