Day 5: Supply Stacks -- AoC 22
stream = File.stream!("/Users/pw/src/weiland/adventofcode/2022/input/05.txt")
Part One
build = fn line, [stack, moves] ->
line = line |> String.replace("\n", "")
if String.starts_with?(line, "move") do
[stack, [line | moves]]
else
[[line | stack], moves]
end
end
[stack, moves] =
stream
|> Enum.reduce([[], []], build)
parse_stack = fn line ->
Regex.scan(~r/\[([A-Z\d])\]|\s{9}/, line, capture: :all_but_first)
# |> Enum.flat_map(fn el -> el end)
|> Enum.map(fn [el] -> el end)
end
stack =
stack
# a bit stateful and hacky :see_no_evil:
|> Enum.map(&String.replace(&1, " ", " [0]"))
# skip empty and the numbers (for now)
|> Enum.drop(2)
|> Enum.map(parse_stack)
# transpose
|> List.zip()
|> Enum.map(&Tuple.to_list/1)
|> Enum.map(&Enum.filter(&1, fn el -> el != "0" end))
parse_moves = fn line ->
[res] = Regex.scan(~r/move ([\d]+) from ([\d]+) to ([\d]+)/, line, capture: :all_but_first)
res
|> Enum.map(&String.to_integer(&1))
end
moves =
moves
|> Enum.map(parse_moves)
|> Enum.reverse()
expand_move = fn move ->
[amount, from, to] = move
cond do
amount > 1 -> List.duplicate([1, from, to], amount)
true -> [move]
end
end
moves1 =
moves
|> Enum.flat_map(expand_move)
exec_move = fn stack, from, to ->
[ilist] =
stack
|> Enum.drop(from - 1)
|> Enum.take(1)
[elem | tail] = ilist |> Enum.reverse()
stack
|> Enum.with_index(1)
|> Enum.map(fn {list, index} ->
cond do
index == from -> Enum.reverse(tail)
index == to -> Enum.reverse([elem | Enum.reverse(list)])
true -> list
end
end)
end
moves1
|> Enum.reduce(stack, fn [_a, from, to], acc -> exec_move.(acc, from, to) end)
|> Enum.map(fn list -> List.last(list) end)
|> Enum.filter(fn item -> item != nil end)
|> List.to_string()
Part Two
exec_move2 = fn stack, amount, from, to ->
[ilist] =
stack
|> Enum.drop(from - 1)
|> Enum.take(1)
ilist = ilist |> Enum.reverse()
elems = Enum.take(ilist, amount)
tail = Enum.drop(ilist, amount)
stack
|> Enum.with_index(1)
|> Enum.map(fn {list, index} ->
cond do
index == from -> Enum.reverse(tail)
index == to -> Enum.reverse(Enum.concat(elems, Enum.reverse(list)))
true -> list
end
end)
end
moves
|> Enum.reduce(stack, fn [amount, from, to], acc -> exec_move2.(acc, amount, from, to) end)
|> Enum.map(fn list -> List.last(list) end)
|> Enum.filter(fn item -> item != nil end)
|> List.to_string()
Code from exec_move2 can also sove Part One.
moves1
|> Enum.reduce(stack, fn [_a, from, to], acc -> exec_move2.(acc, 1, from, to) end)
|> Enum.map(fn list -> List.last(list) end)
|> Enum.filter(fn item -> item != nil end)
|> List.to_string()