Day 6: Guard Gallivant
Mix.install([:kino])
Section
input = Kino.Input.textarea("Input", monospace: true)
map =
input
|> Kino.Input.read()
|> String.split()
|> Enum.map(&String.graphemes/1)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {row, y}, map ->
row
|> Enum.with_index()
|> Enum.reduce(map, fn {col, x}, map ->
Map.put(map, {x, y}, col)
end)
end)
guard = Enum.find(map, fn {_p, g} -> g == "^" end)
defmodule Guard do
def step(guard, map) do
case Map.get(map, guard |> forward() |> elem(0)) do
nil -> :out_of_bounds
"#" -> guard |> rotate() |> step(map)
_ -> forward(guard)
end
end
def forward({{x, y}, "^"}), do: {{x, y - 1}, "^"}
def forward({{x, y}, ">"}), do: {{x + 1, y}, ">"}
def forward({{x, y}, "v"}), do: {{x, y + 1}, "v"}
def forward({{x, y}, "<"}), do: {{x - 1, y}, "<"}
def rotate({p, "^"}), do: {p, ">"}
def rotate({p, ">"}), do: {p, "v"}
def rotate({p, "v"}), do: {p, "<"}
def rotate({p, "<"}), do: {p, "^"}
def walk(guard, map) do
Stream.unfold(guard, fn
:out_of_bounds -> nil
guard -> {guard, step(guard, map)}
end)
end
end
patrol = Guard.walk(guard, map) |> Map.new() |> Map.keys()
Enum.count(patrol)
Enum.count(patrol, fn p ->
guard
|> Guard.walk(Map.put(map, p, "#"))
|> Enum.reduce_while(MapSet.new(), fn guard, path ->
if MapSet.member?(path, guard) do
{:halt, :loop}
else
{:cont, MapSet.put(path, guard)}
end
end) == :loop
end)