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, &(&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(&Task.async(fn -> func.(&1) end))
|> Enum.map(&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()