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

Advent of code day 08

2024/livebooks/day-08.livemd

Advent of code day 08

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

Setup input

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

Parse

parsed =
  example
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&(String.split(&1, "", trim: true) |> List.to_tuple()))
  |> List.to_tuple()

rows = tuple_size(parsed) - 1
cols = tuple_size(elem(parsed, 0)) - 1

grid =
  for l <- 0..rows, c <- 0..cols, into: %{} do
    {{l, c}, elem(elem(parsed, l), c)}
  end

Part 01

defmodule Solver do
  def part01(antennas, {max_row, max_col}) do
    Enum.reduce(antennas, MapSet.new(), fn {_k, coords}, set ->
      crds = List.to_tuple(coords)

      for r <- 0..(length(coords) - 1), c <- 1..(length(coords) - 1), c != r do
        {{r1, c1}, _} = elem(crds, r)
        {{r2, c2}, _} = elem(crds, c)

        a = {2 * r1 - r2, 2 * c1 - c2}
        b = {2 * r2 - r1, 2 * c2 - c1}
        {a, b}
      end
      |> Enum.reduce(set, fn {a, b}, s ->
        MapSet.put(s, a) |> MapSet.put(b)
      end)
    end)
    |> Enum.reject(fn {row, col} ->
      row < 0 or row > max_row or (col < 0 or col > max_col)
    end)
  end

  def part02(antennas, {max_row, max_col}) do
    Enum.reduce(antennas, MapSet.new(), fn {_k, coords}, ss ->
      crds = List.to_tuple(coords)

      for r <- 0..(length(coords) - 1), c <- 0..(length(coords) - 1), c != r do
        {{r1, c1}, _} = elem(crds, r)
        {{r2, c2}, _} = elem(crds, c)
        dr = r2 - r1
        dc = c2 - c1

        rx = r1
        cx = c1

        0
        |> Stream.iterate(&amp;(&amp;1 + 1))
        |> Enum.reduce_while(%{set: MapSet.new(), r: rx, c: cx}, fn _, acc ->
          set = MapSet.put(acc.set, {acc.r, acc.c})

          r = acc.r + dr
          c = acc.c + dc

          cond do
            acc.r < 0 or acc.r > max_row or (acc.c < 0 or acc.c > max_col) ->
              {:halt, acc.set}

            true ->
              {:cont, %{acc | set: set, r: r, c: c}}
          end
        end)
      end
      |> Enum.reduce(ss, fn m, acc ->
        MapSet.union(m, acc)
      end)
    end)
  end
end
antennas = grid |> Enum.group_by(fn {_, v} -> v end ) |> Map.delete(".")


Solver.part01(antennas, {rows, cols})  |> Enum.uniq |> Enum.count

Part 02

Solver.part02(antennas, {rows, cols})  |> MapSet.size()