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

Advent of Code 2023 - Day 12

2023/12.livemd

Advent of Code 2023 - Day 12

Mix.install([
  {:kino, "~> 0.11.0"},
  {:kino_aoc, github: "ljgago/kino_aoc"},
  {:memoize, "~> 1.4"}
])

Input

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "12", System.fetch_env!("LB_AOC_SESSION"))
input =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.map(fn row ->
    [record, checksum] = String.split(row, " ")

    record = String.graphemes(record)

    checksum =
      checksum
      |> String.split(",")
      |> Enum.map(&String.to_integer/1)

    {record, checksum}
  end)

Part 1

Inspired by HyperNeutrino.

defmodule HotSprings do
  use Memoize

  def sum_counts(rows) do
    Memoize.invalidate(__MODULE__)

    for {record, checksum} <- rows, reduce: 0 do
      sum -> sum + HotSprings.count(record, checksum)
    end
  end

  def count(record, []) do
    if "#" in record, do: 0, else: 1
  end

  def count([], []), do: 1

  def count([], _), do: 0

  defmemo count([first | rest] = record, [firstsum | restsum] = checksum) do
    Task.async(fn ->
      if first in [".", "?"] do
        count(rest, checksum)
        |> increase(:result)
      end

      if first in ["#", "?"] do
        if firstsum <= length(record) and
             "." not in Enum.slice(record, 0..(firstsum - 1)) and
             (firstsum == length(record) or Enum.at(record, firstsum) != "#") do
          record
          |> Enum.slice((firstsum + 1)..-1)
          |> count(restsum)
          |> increase(:result)
        end
      end

      Process.get(:result, 0)
    end)
    |> Task.await()
  end

  defp increase(by, key) do
    current = Process.get(key, 0)
    Process.put(key, current + by)
  end
end

input
|> HotSprings.sum_counts()

Part 2

input
|> Enum.map(fn {record, checksum} ->
  record =
    record
    |> List.duplicate(5)
    |> Enum.join("?")
    |> String.graphemes()

  checksum =
    checksum
    |> List.duplicate(5)
    |> List.flatten()

  {record, checksum}
end)
|> HotSprings.sum_counts()

Run in Livebook