AOC 2022-05 (Supply Stacks)
Mix.install([
{:kino, "~> 0.7.0"}
])
Common Code
defmodule Transpose do
def it([[] | _]), do: []
def it(list) when is_list(list) do
[Enum.map(list, &hd/1) | it(Enum.map(list, &tl/1))]
end
end
Input
input = Kino.Input.textarea("Input")
[stacks, instructions] =
input
|> Kino.Input.read()
|> String.split("\n\n")
stacks =
stacks
|> String.split("\n")
|> Enum.map(&String.graphemes/1)
|> Enum.map(fn row ->
row
|> Enum.chunk_every(4)
|> Enum.map(&Enum.at(&1, 1))
end)
|> Enum.drop(-1)
|> Transpose.it()
|> Enum.map(fn row ->
Enum.reject(row, &(&1 == " "))
end)
instructions =
instructions
|> String.split("\n")
|> Enum.map(&String.split/1)
|> Enum.map(fn [_move, n, _fromLabel, from, _toLabel, to] ->
{:move, String.to_integer(n), String.to_integer(from) - 1, String.to_integer(to) - 1}
end)
Part 1
Find the first crate in each stack after processing all moves.
Enum.reduce(instructions, stacks, fn {:move, n, from, to}, acc ->
Enum.map_reduce(1..n, acc, fn _x, acc2 ->
[head | rest] = Enum.at(acc2, from)
acc2 =
acc2
|> List.replace_at(from, rest)
|> List.replace_at(to, [head | Enum.at(acc2, to)])
{nil, acc2}
end)
|> elem(1)
end)
|> Enum.map(&hd/1)
|> Enum.join()
Part 2
Move stacks, but don't their reverse order while moving.
Enum.reduce(instructions, stacks, fn {:move, n, from, to}, acc ->
head = Enum.take(Enum.at(acc, from), n)
rest = Enum.drop(Enum.at(acc, from), n)
acc
|> List.replace_at(from, rest)
|> List.replace_at(to, head ++ Enum.at(acc, to))
end)
|> Enum.map(&hd/1)
|> Enum.join()