1
0
Fork 0
advent-of-code/2023/lib/aoc_helpers/grid.ex
2023-12-11 10:34:19 -05:00

108 lines
2.2 KiB
Elixir

defmodule AOCHelpers.Grid do
import AOCHelpers
defstruct [:map, :bounds]
def to_grid(str) do
lists =
str
|> lines()
|> Enum.map(&letters/1)
map =
for {list, y} <- Enum.with_index(lists), {v, x} <- Enum.with_index(list), into: %{} do
{{x, y}, v}
end
max_x =
map
|> Enum.map(fn {{x, _}, _} -> x end)
|> Enum.max()
max_y =
map
|> Enum.map(fn {{_, y}, _} -> y end)
|> Enum.max()
bounds = {0..max_x, 0..max_y}
%__MODULE__{map: map, bounds: bounds}
end
def in_bounds?(%__MODULE__{bounds: {min_x..max_x, min_y..max_y}}, {x, y}) do
min_x <= x and x <= max_x and min_y <= y and y <= max_y
end
def update!(grid, coords, value) do
%__MODULE__{grid | map: Map.update!(grid.map, coords, value)}
end
def get(grid, coords, default \\ nil) do
Map.get(grid.map, coords, default)
end
def map(grid, fun) do
map =
Enum.map(grid.map, fn {coords, value} ->
{coords, fun.(value)}
end)
|> Enum.into(%{})
%__MODULE__{grid | map: map}
end
def inspect(%__MODULE__{map: map, bounds: bounds}) do
{xs, ys} = bounds
for y <- ys, into: "" do
line =
for x <- xs, into: "" do
Map.get(map, {x, y}, " ")
end
"#{line}\n"
end
|> IO.puts()
end
def find_value(grid, value) do
with {coords, _} <- Enum.find(grid.map, fn {_, v} -> v == value end) do
coords
end
end
def find(grid, fun) do
Enum.find(grid.map, fn {_, v} -> fun.(v) end)
end
def neighbors(grid, coords, diag? \\ false) do
coords
|> neighbor_coords()
|> Enum.filter(fn {c, dirs} ->
if diag? do
in_bounds?(grid, c)
else
in_bounds?(grid, c) and length(dirs) == 1
end
end)
|> Enum.map(fn {c, dirs} ->
{c, dirs, Map.get(grid.map, c)}
end)
end
defp neighbor_coords({x, y}) do
for {j, j_dir} <- [{y - 1, [:north]}, {y, []}, {y + 1, [:south]}],
{i, i_dir} <- [{x - 1, [:west]}, {x, []}, {x + 1, [:east]}],
{x, y} != {i, j} do
{{i, j}, j_dir ++ i_dir}
end
end
end
# defimpl Inspect, for: AOCHelpers.Grid do
# import Inspect.Algebra
# def inspect(grid, opts) do
# end
# end