advent_of_code/lib/range_util.ex

60 lines
1.6 KiB
Elixir

defmodule RangeUtil do
@spec from_start(integer(), integer()) :: Range.t()
def from_start(start, len) do
if len == 0 do
..
else
start..(start + len - 1)
end
end
def transpose(value, source, dest) do
offset = value - (source |> Enum.at(0))
(dest |> Enum.at(0)) + offset
end
@spec contains?(Range.t(), Range.t()) :: boolean
def contains?(r1, r2) do
r2.first >= r1.first and r2.last <= r1.last
end
@spec difference(Range.t(), Range.t()) :: [Range.t()]
def difference(r1, r2) do
cond do
Range.disjoint?(r1, r2) ->
[r1]
RangeUtil.contains?(r2, r1) ->
[]
RangeUtil.contains?(r1, r2) ->
s1_len = r2.first - r1.first
s2_len = r1.last - r2.last
[
RangeUtil.from_start(r1.first, s1_len),
RangeUtil.from_start(r2.last + 1, s2_len)
]
|> Enum.reject(fn r -> r == .. end)
r2.first <= r1.first and r2.last <= r1.last ->
s1_len = r1.last - r2.last
[RangeUtil.from_start(r2.last + 1, s1_len)]
r2.first >= r1.first and r2.last >= r1.last ->
s1_len = r2.first - r1.first
[RangeUtil.from_start(r1.first, s1_len)]
end
end
@spec intersection(Range.t(), Range.t()) :: Range.t()
def intersection(r1, r2) do
cond do
Range.disjoint?(r1, r2) -> ..
RangeUtil.contains?(r2, r1) -> r1
RangeUtil.contains?(r1, r2) -> r2
r2.first <= r1.first and r2.last <= r1.last -> Range.new(r1.first, r2.last)
r2.first >= r1.first and r2.last >= r1.last -> Range.new(r2.first, r1.last)
end
end
end