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

Day 12

2023/day_12.livemd

Day 12

Mix.install([:kino, :memoize])

Get input

input =
  Kino.Input.textarea("Paste input here",
    default: """
    ???.### 1,1,3
    .??..??...?##. 1,1,3
    ?#?#?#?#?#?#?#? 1,3,1,6
    ????.#...#... 4,1,1
    ????.######..#####. 1,6,5
    ?###???????? 3,2,1
    """
  )
damage_report =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Stream.map(fn line -> String.split(line, " ", trim: true) end)
  |> Enum.map(fn [springs, groups] ->
    {String.split(springs, "", trim: true),
     groups |> String.split(",", trim: true) |> Enum.map(&String.to_integer/1)}
  end)
defmodule HotSprings do
  use Memoize

  defmemo(combinations(["." | tail], checksum), do: combinations(tail, checksum))

  defmemo combinations(["?" | tail], checksum) do
    combinations(["#" | tail], checksum) + combinations(["." | tail], checksum)
  end

  defmemo(combinations([], []), do: 1)
  defmemo(combinations([_head | _tail], []), do: 0)
  defmemo(combinations([], [_head | _tail]), do: 0)

  defmemo combinations(["#" | _tail] = springs, [check_group_length | rest_checksum]) do
    {group, rest} = Enum.split(springs, check_group_length)

    current_group_length = Enum.count(group)

    cond do
      current_group_length < check_group_length ->
        0

      Enum.all?(group, &amp;(&amp;1 !== ".")) ->
        case rest do
          ["#" | _t] -> 0
          ["?" | t] -> combinations(["." | t], rest_checksum)
          _ -> combinations(rest, rest_checksum)
        end

      true ->
        0
    end
  end
end
defmodule Parallel do
  def pmap(collection, func) do
    collection
    |> Enum.map(&amp;Task.async(fn -> func.(&amp;1) end))
    |> Enum.map(&amp;Task.await/1)
  end
end

Part 1

damage_report
|> Parallel.pmap(fn {springs, checksum} ->
  HotSprings.combinations(springs, checksum)
end)
|> Enum.sum()
|> dbg()

Part 2

damage_report
|> Enum.map(fn {streams, checksum} ->
  unfolded_streams =
    1..5 |> Enum.map(fn _ -> streams end) |> Enum.intersperse(["?"]) |> List.flatten()

  unfolded_checksums = Enum.flat_map(1..5, fn _ -> checksum end)
  {unfolded_streams, unfolded_checksums}
end)
|> Parallel.pmap(fn {springs, checksum} ->
  HotSprings.combinations(springs, checksum)
end)
|> Enum.sum()
|> dbg()