Powered by AppSignal & Oban Pro

Day 5

2022/day05.livemd

Day 5

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

Input

input = Kino.Input.textarea("")

Pre-work

defmodule Stacks do
  def top_crates(stacks) do
    1..Enum.count(stacks) |> Enum.map(&hd(stacks[&1])) |> List.to_string()
  end

  def process_moves(stacks, moves, reverse \\ false) do
    Enum.reduce(moves, stacks, fn {qty, i, j}, acc ->
      {removed, remaining} = Enum.split(acc[i], qty)
      to_add = if reverse, do: Enum.reverse(removed), else: removed
      %{acc | i => remaining, j => to_add ++ acc[j]}
    end)
  end
end

[stacks_section, moves_section] = input |> Kino.Input.read() |> String.split("\n\n")
[numbers_row | elements_rows] = stacks_section |> String.split("\n") |> Enum.reverse()
stacks_len = numbers_row |> String.split() |> List.last() |> String.to_integer()
empty_stacks = Map.new(1..stacks_len, fn i -> {i, []} end)

stacks =
  Enum.reduce(elements_rows, empty_stacks, fn row, stacks_0 ->
    char_list = String.to_charlist(row)

    Enum.reduce(1..stacks_len, stacks_0, fn i, stacks_1 ->
      c = Enum.at(char_list, (i - 1) * 4 + 1)
      if c == 32, do: stacks_1, else: Map.update!(stacks_1, i, &[c | &1])
    end)
  end)

moves =
  moves_section
  |> String.split()
  |> Enum.chunk_every(6)
  |> Enum.map(fn [_, qty, _, i, _, j] ->
    {String.to_integer(qty), String.to_integer(i), String.to_integer(j)}
  end)

Part 1

stacks |> Stacks.process_moves(moves, true) |> Stacks.top_crates()

Part 2

stacks |> Stacks.process_moves(moves) |> Stacks.top_crates()