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

Day 12: Hot springs – Advent of Code 2023

2023/12.livemd

Day 12: Hot springs – Advent of Code 2023

input =
  File.stream!("/Users/pw/src/weiland/adventofcode/2023/input/12.txt")
  |> Stream.map(&String.trim/1)

test_input = "???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1" |> String.split("\n")

correct_test_input = "#.#.### 1,1,3
.#...#....###. 1,1,3
.#.###.#.###### 1,3,1,6
####.#...#... 4,1,1
#....######..#####. 1,6,5
.###.##....# 3,2,1" |> String.split("\n")

Parsing

unfold = fn input, times ->
  input
  |> Enum.map(&String.split(&1, " "))
  |> Enum.map(fn [conditions_string, groups_string] ->
    conditions = List.duplicate(conditions_string, times) |> Enum.join("?") |> String.graphemes()

    groups =
      groups_string
      |> String.split(",")
      |> Enum.map(&String.to_integer/1)
      |> List.duplicate(times)
      |> List.flatten()

    {conditions, groups}
  end)
end

Part One

defmodule HotSprings do
  def get_arrangements([], []), do: 1
  def get_arrangements([], _groups), do: 0

  def get_arrangements(conditions, []) do
    if Enum.member?(conditions, "#"), do: 0, else: 1
  end

  def get_arrangements(conditions, groups) do
    condition = Enum.at(conditions, 0)
    group = Enum.at(groups, 0)

    # non damaged
    result =
      if condition == "." || condition == "?",
        do: get_arrangements(tl(conditions), groups),
        else: 0

    # damaged
    if (condition == "#" || condition == "?") &&
         group <= Enum.count(conditions) &amp;&amp;
         !Enum.member?(Enum.slice(conditions, 0, group), ".") &amp;&amp;
         (group == Enum.count(conditions) || Enum.at(conditions, group) != "#") do
      result + get_arrangements(Enum.drop(conditions, group + 1), tl(groups))
    else
      result
    end
  end

  # TODO: memoization for part two
end
part_one = fn input ->
  input
  |> unfold.(1)
  |> Enum.map(fn {r, n} -> HotSprings.get_arrangements(r, n) end)
  |> Enum.sum()
end

part_one.(test_input) == 21 &amp;&amp;
part_one.(input)

Part Two

part_two = fn input ->
  input
  |> unfold.(5)
  |> Enum.map(fn {conditions, groups} -> HotSprings.get_arrangements(conditions, groups) end)
  |> Enum.sum
end

part_two.(test_input) == 525152
part_two.(input)