aoc/22/lib/days/day5.ex

71 lines
1.6 KiB
Elixir
Raw Permalink Normal View History

2023-04-17 18:18:20 +00:00
defmodule AOC.Day5 do
use AOC.Day, day: 5, trim: false
def parse_input(lines) do
[init, ops] =
lines
|> Enum.chunk_by(&(&1 == "\n"))
|> Enum.reject(&(&1 == ["\n"]))
{parse_init(init), parse_ops(ops)}
end
def parse_init(init) do
init
|> Enum.split(-1)
|> elem(0)
|> Enum.map(fn line ->
line
|> String.to_charlist()
|> tl()
|> Enum.take_every(4)
end)
|> Enum.zip_with(&Function.identity/1)
|> Enum.map(fn stack ->
Enum.reject(stack, &(&1 == ?\s))
end)
end
def parse_ops(ops) do
Enum.map(ops, fn op ->
%{"count" => count, "from" => from, "to" => to} =
Regex.named_captures(~r/move (?<count>\d+) from (?<from>\d+) to (?<to>\d+)\n/, op)
%{
count: String.to_integer(count),
from: String.to_integer(from) - 1,
to: String.to_integer(to) - 1
}
end)
end
def part1(input) do
move(input, true)
end
def part2(input) do
move(input, false)
end
def move({init, ops}, reverse) do
ops
|> Enum.reduce(init, fn %{count: count, from: from, to: to}, acc ->
{acc, removed} = remove(acc, from, count)
removed = if reverse, do: Enum.reverse(removed), else: removed
add(acc, to, removed)
end)
|> Enum.map(&hd/1)
end
def remove(stacks, from, count) do
{removed, new} = Enum.split(Enum.at(stacks, from), count)
stacks = List.update_at(stacks, from, fn _ -> new end)
{stacks, removed}
end
def add(stacks, to, removed) do
added = Enum.concat(removed, Enum.at(stacks, to))
List.update_at(stacks, to, fn _ -> added end)
end
end