AoC18/lib/day3/day3.ex

95 lines
2.1 KiB
Elixir
Raw Normal View History

2018-12-03 21:41:40 +00:00
defmodule Day3 do
defmodule Rect do
defstruct [:id, :left, :top, :width, :height]
def points(nil), do: []
2018-12-03 21:58:13 +00:00
2018-12-03 21:41:40 +00:00
def points(rect) do
xs = rect.left..(rect.left + rect.width - 1)
2018-12-03 21:58:13 +00:00
2018-12-03 21:41:40 +00:00
Enum.flat_map(xs, fn x ->
ys = rect.top..(rect.top + rect.height - 1)
Enum.map(ys, fn y -> {x, y} end)
end)
end
def overlap(a, b) do
overlap_left = max(a.left, b.left)
2018-12-03 21:58:13 +00:00
overlap_width = max(0, min(a.left + a.width, b.left + b.width) - overlap_left)
2018-12-03 21:41:40 +00:00
overlap_top = max(a.top, b.top)
overlap_height = max(0, min(a.top + a.height, b.top + b.height) - overlap_top)
2018-12-03 21:58:13 +00:00
2018-12-03 21:41:40 +00:00
case overlap_width * overlap_height do
0 ->
nil
2018-12-03 21:58:13 +00:00
2018-12-03 21:41:40 +00:00
_ ->
2018-12-03 21:58:13 +00:00
%Rect{
left: overlap_left,
top: overlap_top,
width: overlap_width,
height: overlap_height
}
2018-12-03 21:41:40 +00:00
end
end
end
def parse_rect(str) do
parts = Regex.run(~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/, str)
2018-12-03 21:58:13 +00:00
2018-12-03 21:41:40 +00:00
%Rect{
2018-12-03 21:58:13 +00:00
id: parts |> Enum.at(1) |> String.to_integer(),
left: parts |> Enum.at(2) |> String.to_integer(),
top: parts |> Enum.at(3) |> String.to_integer(),
width: parts |> Enum.at(4) |> String.to_integer(),
height: parts |> Enum.at(5) |> String.to_integer()
2018-12-03 21:41:40 +00:00
}
end
def except(list, except) do
Enum.reject(list, fn el -> el == except end)
end
def overlap_area(rects) do
rects
2018-12-03 21:58:13 +00:00
|> Enum.flat_map(fn rect ->
rects
|> except(rect)
|> Enum.map(fn other ->
Rect.overlap(rect, other)
2018-12-03 21:41:40 +00:00
end)
2018-12-03 21:58:13 +00:00
|> Enum.flat_map(&Rect.points/1)
end)
|> Enum.uniq()
|> Enum.count()
2018-12-03 21:41:40 +00:00
end
def exclude_overlapping(rects) do
rects
2018-12-03 21:58:13 +00:00
|> Enum.reject(fn rect ->
rects
|> except(rect)
|> Enum.any?(fn other ->
Rect.overlap(rect, other) != nil
2018-12-03 21:41:40 +00:00
end)
2018-12-03 21:58:13 +00:00
end)
2018-12-03 21:41:40 +00:00
end
def parse_input() do
File.read!("lib/day3/input.txt")
2018-12-03 21:58:13 +00:00
|> String.split("\n", trim: true)
2018-12-03 21:41:40 +00:00
end
def part1() do
parse_input()
2018-12-03 21:58:13 +00:00
|> Enum.map(&parse_rect/1)
|> overlap_area()
2018-12-03 21:41:40 +00:00
end
def part2() do
parse_input()
2018-12-03 21:58:13 +00:00
|> Enum.map(&parse_rect/1)
|> exclude_overlapping()
2018-12-03 21:41:40 +00:00
end
2018-12-03 21:58:13 +00:00
end