Skip to content

Instantly share code, notes, and snippets.

@jemmyw
Created December 9, 2018 21:18
Show Gist options
  • Save jemmyw/d70f6c0e2614e1761a50f640f9078d35 to your computer and use it in GitHub Desktop.
Save jemmyw/d70f6c0e2614e1761a50f640f9078d35 to your computer and use it in GitHub Desktop.
defmodule Danger do
def parse(str) when is_bitstring(str) do
str
|> String.split("\n")
|> parse()
|> Enum.with_index()
|> Enum.map(fn {c, i} ->
{c, [?a + i] |> to_string}
end)
end
def parse([]), do: []
def parse([str | t]) do
[
str |> String.split(~r/, /) |> Enum.map(&String.to_integer(&1)) |> List.to_tuple()
| parse(t)
]
end
def unindex({c, _}), do: c
def distance({x1, y1}, {x2, y2}) do
abs(x1 - x2) + abs(y1 - y2)
end
def total_distance(_, []), do: 0
def total_distance(c, [h | t]) do
distance(c, h |> unindex) + total_distance(c, t)
end
# Get the owning coordinate of a coord
def coord_id(coord, list, closest \\ {nil, -1})
# no list, return acc
def coord_id(_, [], {c, _}), do: c
# self return self
def coord_id(coord, [{coord, index} | _], _), do: {coord, index |> String.upcase()}
# no acc, recurse with head
def coord_id(coord, [h | t], {nil, -1}) do
coord_id(coord, t, {h, distance(coord, h |> unindex)})
end
# acc, calc if next distance is shorter
def coord_id(coord, [h | t], {c, d}) do
new_distance = distance(coord, h |> unindex)
# IO.inspect([coord, h |> unindex, d, new_distance])
cond do
new_distance < d -> coord_id(coord, t, {h, new_distance})
new_distance > d -> coord_id(coord, t, {c, d})
new_distance == d -> coord_id(coord, t, {nil, d})
end
end
def grid_size(list) do
list
|> Enum.map(&unindex/1)
|> Enum.reduce({0, 0}, fn {x1, y1}, {x2, y2} ->
{max(x1, x2), max(y1, y2)}
end)
end
def infinite?({_, i}, list) do
{w, h} = Danger.grid_size(list)
Enum.any? [
{-1..w+1, [-1]},
{-1..w+1, [h+1]},
{[-1], -1..h+1},
{[w+1], -1..h+1}
], fn {xr, yr} ->
Enum.any? xr, fn x ->
Enum.any? yr, fn y ->
case coord_id({x, y}, list) do
{_, ^i} -> true
_ -> false
end
end
end
end
end
def size({_, i}, list) do
{w, h} = Danger.grid_size(list)
Enum.reduce 0..h, 1, fn y, s ->
Enum.reduce 0..w, s, fn x, s ->
case coord_id({x, y}, list) do
{_, ^i} -> s + 1
_ -> s
end
end
end
end
def size_region_lower_than(list, l) do
{w, h} = Danger.grid_size(list)
Enum.reduce 0..h, 0, fn y, s ->
Enum.reduce 0..w, s, fn x, s ->
d = total_distance({x, y}, list)
cond do
d < l -> s + 1
true -> s
end
end
end
end
def biggest(out_of, list) do
Enum.reduce out_of, {nil, 0}, fn c, {p, s} ->
next_size = Danger.size(c, list)
cond do
next_size > s -> {c, next_size}
true -> {p, s}
end
end
end
def draw_grid(list) do
{w, h} = Danger.grid_size(list)
Enum.each(0..(h + 1), fn y ->
Enum.each(0..(w + 1), fn x ->
owner = Danger.coord_id({x, y}, list)
case owner do
nil -> IO.write(".")
{_, i} -> IO.write(i)
end
end)
IO.write("\n")
end)
end
end
list = File.read("6.txt") |> elem(1) |> Danger.parse()
# Part 1
list |> Enum.reject(&(Danger.infinite?(&1, list))) |> Danger.biggest(list) |> IO.inspect()
# Part 2
list |> Danger.size_region_lower_than(10000) |> IO.inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment