Advent of Code: Day 05
Helpers
defmodule Helpers do
@spec read_file_contents(String.t()) :: {:ok, binary()}
def read_file_contents(filename) do
file_path = "/Users/charlie/github.com/charlieroth/advent-of-code/2022/#{filename}"
case File.read(file_path) do
{:ok, contents} -> contents
{:error, _} -> raise("Failed to read file contents")
end
end
end
defmodule Stack do
defstruct items: []
def new, do: %Stack{}
def size(%Stack{items: items}), do: length(items)
def push(%Stack{items: items}, item), do: %Stack{items: [item | items]}
def pop(%Stack{items: [item | rest]}), do: {item, %Stack{items: rest}}
def pop(stack = %Stack{items: []}), do: {nil, stack}
end
Part 01
The Elves just need to know which crate will end up on top of each stack
In this example, the top crates are C
in stack 1
, M
in stack 2
, and Z
in stack 3
, so you should combine these together and give the Elves the message CMZ
.
input = ~S"""
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
"""
[stacks, moves] = input |> String.split("\n\n", trim: true)
# https://elixirforum.com/t/advent-of-code-2022-day-5/52258/2
stacks =
stacks
|> String.split("\n", trim: true)
|> Enum.drop(-1)
# list({char(), integer()})
|> Enum.flat_map(fn line ->
line
# list(char())
|> String.graphemes()
# remove first empty string
|> Enum.drop(1)
# take the 0th and every 4th element
|> Enum.take_every(4)
# tuple {character, index}
|> Enum.with_index(1)
end)
# group by index into map(String.t(), { String.t(), integer() })
|> Enum.group_by(&elem(&1, 1))
# transform map(String.t(), tuple(String.t(), integer())) into list(tuple(integer(), list(String.t())))
|> Enum.map(fn {column, vals} ->
# take the character from tuple(String.t(), integer())
# remove empty ("") characters
val =
vals
|> Enum.map(&elem(&1, 0))
|> Enum.filter(&(&1 !== " "))
{column, val}
end)
# transform list(tuple(integer(), list(String.t()))) to map(integer(), list(String.t()))
|> Map.new()
moves =
moves
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split(["move ", " from ", " to "], trim: true)
|> Enum.map(&String.to_integer(&1))
end)
defmodule PartOne do
def move([n, from, to], s) do
1..n
|> Enum.reduce(s, fn _, new_stacks ->
case Map.get(new_stacks, from) do
nil ->
new_stacks
[] ->
new_stacks
# pop crate from bottom of "from" stack
[crate | from_stack] ->
to_stack = Map.get(new_stacks, to)
new_stacks
|> Map.put(from, from_stack)
|> Map.put(to, [crate | to_stack])
end
end)
end
end
final_stack =
[[1, 2, 1], [3, 1, 3], [2, 2, 1], [1, 1, 2]]
|> Enum.map(fn instruction ->
PartOne.move(instruction, stacks)
end)
|> List.last()
m = %{1 => ["N", "Z"]}
[a | b] = Map.get(m, 1)
a
Part 02