Powered by AppSignal & Oban Pro

Advent of Code 2023

aoc2023.livemd

Advent of Code 2023

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

Day 1

input1a = Kino.Input.textarea("Input")
input1a
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(&(Regex.run(~r/\d/, &1) ++ Regex.run(~r/.*\K\d/, &1)))
|> Enum.map(&(Enum.join(&1) |> String.to_integer()))
|> Enum.sum()
input1b = Kino.Input.textarea("Input")
m =
  ~w"one two three four five six seven eight nine"
  |> Enum.with_index(1)
  |> Enum.into(Map.new(1..9, &{"#{&1}", &1}))

p1 = ~r/#{Enum.join(Map.keys(m), "|")}/
p2 = ~r/.*\K(#{Regex.source(p1)})/

input1b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(&(m[hd(Regex.run(p1, &1))] * 10 + m[hd(Regex.run(p2, &1))]))
|> Enum.sum()

Day 2

input2a = Kino.Input.textarea("Input")
input2a
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.flat_map(fn s ->
  ["Game " <> i, t] = String.split(s, ": ")

  String.split(t)
  |> Enum.chunk_every(2)
  |> Enum.map(fn [n, c] -> {String.first(c), String.to_integer(n)} end)
  |> Enum.all?(fn {c, n} -> %{"r" => 12, "g" => 13, "b" => 14}[c] >= n end)
  |> if do
    [String.to_integer(i)]
  else
    []
  end
end)
|> Enum.sum()
input2b = Kino.Input.textarea("Input")
input2b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn s ->
  [_, t] = String.split(s, ": ")

  String.split(t)
  |> Enum.chunk_every(2)
  |> Enum.map(fn [n, c] -> {String.first(c), String.to_integer(n)} end)
  |> Enum.reduce(Map.from_keys(~w"r g b", 0), fn {c, n}, m -> %{m | c => max(m[c], n)} end)
  |> Map.values()
  |> Enum.product()
end)
|> Enum.sum()

Day 3

input3a = Kino.Input.textarea("Input")
input3b = Kino.Input.textarea("Input")
input3b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.with_index()
|> Enum.flat_map(fn {s, i} ->
  Regex.scan(~r/(\d+)|([#$%&*+\-\/=@])/, s, capture: :all_but_first, return: :index)
  |> Enum.map(fn
    [{-1, 0}, {j, 1}] -> {String.at(s, j), i, j}
    [{j, n}] -> {String.slice(s, j..(j + n - 1)), i, j, n}
  end)
end)
|> Enum.reduce({[], %{}}, fn
  {s, i, j}, {a, b} -> {a, Map.put(b, {i, j}, s)}
  {s, i, j, n}, {a, b} -> {[{s |> String.to_integer(), i, j, n} | a], b}
end)
|> then(fn {a, b} ->
  a
  |> Enum.flat_map(fn {d, i, j, n} ->
    for(i <- (i - 1)..(i + 1), j <- (j - 1)..(j + n), do: b[{i, j}] != nil)
    |> Enum.any?()
    |> if do
      [d]
    else
      []
    end
  end)
end)
|> Enum.sum()
input3b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.with_index()
|> Enum.flat_map(fn {s, i} ->
  Regex.scan(~r/(\d+)|([#$%&*+\-\/=@])/, s, capture: :all_but_first, return: :index)
  |> Enum.map(fn
    [{-1, 0}, {j, 1}] -> {String.at(s, j), i, j}
    [{j, n}] -> {String.slice(s, j..(j + n - 1)), i, j, n}
  end)
end)
|> Enum.reduce({[], %{}}, fn
  {s, i, j}, {a, b} -> {a, Map.put(b, {i, j}, s)}
  {s, i, j, n}, {a, b} -> {[{s |> String.to_integer(), i, j, n} | a], b}
end)
|> then(fn {a, b} ->
  a
  |> Enum.flat_map(fn {d, i, j, n} ->
    for(i <- (i - 1)..(i + 1), j <- (j - 1)..(j + n), do: {i, j})
    |> Enum.flat_map(fn {i, j} -> if b[{i, j}] == "*", do: [{d, i, j}], else: [] end)
  end)
  |> Enum.reduce(%{}, fn {d, i, j}, acc -> Map.update(acc, {i, j}, [d], &amp;[d | &amp;1]) end)
  |> Enum.flat_map(fn {_, v} -> if length(v) == 2, do: [Enum.product(v)], else: [] end)
end)
|> Enum.sum()

Day 4

input4a = Kino.Input.textarea("Input")
input4b = Kino.Input.textarea("Input")
input4b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn s ->
  [_, a, b] = String.split(s, [":", "|"])
  a = String.split(a, " ", trim: true) |> MapSet.new()
  b = String.split(b, " ", trim: true) |> MapSet.new()
  Integer.pow(2, MapSet.intersection(a, b) |> MapSet.size()) |> div(2)
end)
|> Enum.sum()
input4b
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn s ->
  [_, a, b] = String.split(s, [":", "|"])
  a = String.split(a, " ", trim: true) |> MapSet.new()
  b = String.split(b, " ", trim: true) |> MapSet.new()
  MapSet.intersection(a, b) |> MapSet.size()
end)
|> Enum.reduce({0, []}, fn
  n, {r, []} ->
    {r + 1, List.duplicate(1, n)}

  # |> IO.inspect(label: "#{n} #{r} []")
  n, {r, [h | t]} ->
    {r + h + 1,
     Enum.zip(
       List.duplicate(h + 1, n) ++ List.duplicate(0, max(n, length(t)) - n),
       t ++ List.duplicate(0, max(n, length(t)) - length(t))
     )
     |> Enum.map(fn {x, y} -> x + y end)}

    # |> IO.inspect(label: "#{n} #{r} #{inspect [h|t]}")
end)
|> then(fn {r, _} -> r end)

Day 5

input5a = Kino.Input.textarea("Input")
input5b = Kino.Input.textarea("Input")
input5a
|> Kino.Input.read()
|> String.split("\n\n", trim: true)
|> then(fn ["seeds: " <> h | t] ->
  seeds = h |> String.split() |> Enum.map(&amp;String.to_integer/1)

  maps =
    for s <- Enum.map(t, &amp;(String.split(&amp;1, "\n") |> tl)) do
      Enum.map(s, &amp;(String.split(&amp;1) |> Enum.map(fn i -> String.to_integer(i) end)))
    end

  maps
  |> Enum.reduce(seeds, fn map, acc ->
    for i <- acc do
      case Enum.find(map, fn [_a, b, n] -> b <= i and i < b + n end) do
        nil -> i
        [a, b, _n] -> a + (i - b)
      end
    end
  end)
end)
|> IO.inspect(charlists: :as_lists)
|> Enum.min()
sections =
  input5a
  |> Kino.Input.read()
  |> String.split("\n\n", trim: true)

seeds =
  sections
  |> hd()
  |> String.split()
  |> tl()
  |> Enum.map(&amp;String.to_integer(&amp;1))
  |> Enum.chunk_every(2)
  |> Enum.map(fn [start, len] -> {start, start + len - 1} end)

maps =
  sections
  |> tl()
  |> Enum.map(fn map ->
    String.split(map, "\n")
    |> tl()
    |> Enum.map(fn segment ->
      [dst, src, len] =
        segment
        |> String.split()
        |> Enum.map(&amp;String.to_integer/1)

      {{src, src + len - 1}, {dst, dst + len - 1}}
    end)
  end)

defmodule Day5 do
  def tr(_seed = {a, b}, _seg = {{c, d}, {e, f}}) do
    cond do
      # a b c d || c d a b
      b < c or d < a -> [{a, b}]
      # c a b d
      c <= a and b <= d -> [{e + a - c, e + b - c}]
      # a c b d
      a < c and c <= b and b <= d -> [{a, c - 1}, {e, e + b - c}]
      # c a d b
      c <= a and a <= d and d < b -> [{e + a - c, d}, {d + 1, b}]
      # a c d b
      a < c and d < b -> [{a, c - 1}, {c, d}, {d + 1, b}]
    end
    |> IO.inspect(label: inspect(seed: {a, b}, seg: {{c, d}, {e, f}}))
  end

  def tr(seeds = [_ | _], seg = {_, _}) do
    Enum.flat_map(seeds, fn seed -> tr(seed, seg) end)
    |> IO.inspect(label: inspect(seeds: seeds, seg: seg))
  end

  def tr(seed = {_, _}, map = [{_, _} | _]) do
    # XXX TODO
    tr([seed], map)
    |> IO.inspect(label: inspect(seed: seed, map: map))
  end

  def tr(seeds = [_ | _], map = [{_, _} | _]) do
    # XXX
    Enum.reduce(map, seeds, fn seg, acc -> tr(acc, seg) end)
    |> IO.inspect(label: inspect(seeds: seeds, map: map))
  end

  def tr(seed = {_, _}, maps = [[_ | _] | _]) do
    tr([seed], maps)
    |> IO.inspect(label: inspect(seed: seed, maps: maps))
  end

  def tr(seeds = [_ | _], maps = [[_ | _] | _]) do
    Enum.reduce(maps, seeds, fn map, acc -> tr(acc, map) end)
    |> IO.inspect(label: inspect(seeds: seeds, maps: maps))
  end
end

# Day5.tr(hd(seeds), ((maps)))
Day5.tr({82, 82}, maps)
|> IO.inspect()
|> Enum.min()