Day 05
Setup
Mix.install([
{:kino, "~> 0.4.1"}
])
example_input = Kino.Input.textarea("example input:")
real_input = Kino.Input.textarea("real input:")
defmodule Grid do
@enforce_keys [:coordinates]
defstruct coordinates: %{}
def new(x_size, y_size) do
for x <- 0..x_size, y <- 0..y_size, into: %{} do
{{x, y}, 0}
end
|> then(&struct!(__MODULE__, coordinates: &1))
end
def place(grid, []), do: grid
def place(%{coordinates: coordinates} = grid, [coord | rest]) do
place(%{grid | coordinates: update_in(coordinates, [coord], &(&1 + 1))}, rest)
end
def points_gte(grid, value) do
grid.coordinates
|> Map.values()
|> Enum.count(&(&1 >= value))
end
end
defmodule Line do
@enforce_keys [:coord1, :coord2]
defstruct coord1: [], coord2: []
def new([coord1, coord2]) do
struct!(__MODULE__, coord1: coord1, coord2: coord2)
end
def coordinates(%__MODULE__{coord1: [x1, y1], coord2: [x2, y2]})
when x1 == x2 or y1 == y2 do
for x <- x1..x2, y <- y1..y2, do: {x, y}
end
def coordinates(%{coord1: [x1, y1], coord2: [x2, y2]}) do
Enum.zip(x1..x2, y1..y2)
end
def valid?(%__MODULE__{coord1: [x, _], coord2: [x, _]}), do: true
def valid?(%__MODULE__{coord1: [_, y], coord2: [_, y]}), do: true
def valid?(_), do: false
def x_max(%__MODULE__{coord1: [x1, _], coord2: [x2, _]}), do: Enum.max([x1, x2])
def y_max(%__MODULE__{coord1: [_, y1], coord2: [_, y2]}), do: Enum.max([y1, y2])
end
to_integer = &String.to_integer/1
lines =
real_input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, [",", " -> "], trim: true))
|> Enum.map(&Enum.map(&1, to_integer))
|> Enum.map(&Enum.chunk_every(&1, 2))
|> Enum.map(&Line.new/1)
[x_max, y_max] =
lines
|> Enum.reduce([0, 0], fn line, [x, y] ->
[[x, Line.x_max(line)], [y, Line.y_max(line)]]
|> Enum.map(&Enum.max/1)
end)
Part 1
final_grid =
lines
|> Enum.filter(&Line.valid?/1)
|> Enum.reduce(Grid.new(x_max + 1, y_max + 1), fn line, grid ->
Grid.place(grid, Line.coordinates(line))
end)
Grid.points_gte(final_grid, 2)
Part 2
final_grid =
lines
|> Enum.reduce(Grid.new(x_max + 1, y_max + 1), fn line, grid ->
Grid.place(grid, Line.coordinates(line))
end)
Grid.points_gte(final_grid, 2)