Supply Stacks
Mix.install([{:kino, "~> 0.7.0"}])
Input
input = Kino.Input.textarea("Input:")
[stacks, instructions] = Kino.Input.read(input) |> String.trim_trailing() |> String.split("\n\n")
stacks = stacks |> String.split("\n")
{_, stacks} = List.pop_at(stacks, -1)
instructions = instructions |> String.split("\n")
defmodule Stacks do
def new(stacks) do
stacks = Enum.reverse(stacks)
push_layers(stacks, %{})
end
def tops(stacks) do
Map.to_list(stacks) |> Enum.sort() |> Enum.map(fn {_, [top | _]} -> top end)
# Enum.reduce("", fn {_, [top | _]}, acc -> acc <> <> end)
end
defp push_layers([layer | more], acc) do
IO.puts("#{layer}")
acc = push_layer(layer, 1, acc)
push_layers(more, acc)
end
defp push_layers([], acc), do: acc
defp push_layer(<<"[", ch, "] ", rest::binary>>, index, acc) do
acc = push(ch, index, acc)
push_layer(rest, index + 1, acc)
end
defp push_layer(<<"[", ch, "]">>, index, acc) do
push(ch, index, acc)
end
defp push_layer(<<" ", rest::binary>>, index, acc) do
push_layer(rest, index + 1, acc)
end
defp push_layer(<<" ">>, index, acc) do
acc
end
defp push(crate, index, acc) do
Map.update(acc, index, [crate], fn stack -> [crate | stack] end)
end
end
stacks = Stacks.new(stacks)
re = ~r/^move (\d+) from (\d+) to (\d+)/
instructions =
Enum.map(instructions, fn instr ->
[count, from, to] =
Regex.run(re, instr, capture: :all_but_first)
|> Enum.map(&String.to_integer/1)
%{count: count, from: from, to: to}
end)
defmodule Crane9000 do
def run(stacks, [%{count: count, from: from, to: to} | instructions]) do
run(execute(stacks, count, from, to), instructions)
end
def run(stacks, []), do: stacks
defp execute(stacks, 0, _, _), do: stacks
defp execute(stacks, count, from, to) do
{crate, stacks} = pop(stacks, from)
stacks = push(stacks, to, crate)
execute(stacks, count - 1, from, to)
end
defp pop(stacks, from) do
Map.get_and_update(stacks, from, fn [crate | stack] -> {crate, stack} end)
end
defp push(stacks, to, crate) do
Map.update(stacks, to, [crate], fn stack -> [crate | stack] end)
end
end
part1 = Crane9000.run(stacks, instructions)
Stacks.tops(part1) |> List.to_string()
defmodule Crane9001 do
def run(stacks, [%{count: count, from: from, to: to} | instructions]) do
run(execute(stacks, count, from, to), instructions)
end
def run(stacks, []), do: stacks
defp execute(stacks, count, from, to) do
{crates, stacks} = pop(stacks, count, from)
push(stacks, to, crates)
end
defp pop(stacks, count, from) do
Map.get_and_update(stacks, from, fn stack -> Enum.split(stack, count) end)
end
defp push(stacks, to, crates) do
Map.update(stacks, to, crates, fn stack -> crates ++ stack end)
end
end
part2 = Crane9001.run(stacks, instructions)
Stacks.tops(part2) |> List.to_string()