Powered by AppSignal & Oban Pro

Day 5: Supply Stacks

2022/day05.livemd

Day 5: Supply Stacks

Mix.install([:kino])

Section

input = Kino.Input.textarea("Input")
[crates, instructions] =
  input
  |> Kino.Input.read()
  |> String.split("\n\n")

crates =
  crates
  |> String.split("\n")
  |> Enum.drop(-1)
  |> Enum.map(fn line ->
    line
    |> String.graphemes()
    |> Enum.chunk_every(4)
    |> Enum.map(&Enum.at(&1, 1))
  end)
  |> Enum.zip_with(& &1)
  |> Enum.map(&Enum.reject(&1, fn c -> c == " " end))
  |> Enum.with_index(1)
  |> Map.new(fn {v, k} -> {k, v} end)

instructions =
  instructions
  |> String.split(["move ", " from ", " to ", "\n"], trim: true)
  |> Enum.map(&String.to_integer/1)
  |> Enum.chunk_every(3)

defmodule Crane do
  def lift([n, from, to], crates, model \\ 9000) do
    crates
    |> Map.get_and_update(from, &Enum.split(&1, n))
    |> then(fn {load, crates} ->
      case model do
        9000 -> Map.update!(crates, to, &(Enum.reverse(load) ++ &1))
        9001 -> Map.update!(crates, to, &(load ++ &1))
      end
    end)
  end
end

Part 1

instructions
|> Enum.reduce(crates, &Crane.lift/2)
|> Map.values()
|> Enum.map(&hd/1)
|> Enum.join()

Part 2

instructions
|> Enum.reduce(crates, &Crane.lift(&1, &2, 9001))
|> Map.values()
|> Enum.map(&hd/1)
|> Enum.join()