defmodule Day10 do def part1(data) do grid = data |> String.split("\n", trim: true) |> Enum.map(&String.codepoints/1) |> Enum.map(fn v -> Enum.map(v, &String.to_integer/1) end) values = for {l, i} <- Enum.with_index(grid), {v, j} <- Enum.with_index(l) do {v, {i, j}} end |> Enum.group_by(fn {v, _} -> v end, fn {_, p} -> p end) dist = fn {a, b}, {c, d} -> abs(a-c) + abs(b-d) end ends = fn p, prev -> for {_, v} <- Enum.filter(prev, fn {p2, _} -> dist.(p, p2) == 1 end), reduce: MapSet.new() do acc -> MapSet.union(acc, v) end end for i <- 8..0//-1, reduce: Map.get(values, 9, []) |> Enum.map(& {&1, MapSet.new([&1])}) do acc -> Map.get(values, i, []) |> Enum.map(fn p -> {p, ends.(p, acc)} end) |> Enum.filter(fn {_, m} -> MapSet.size(m) > 0 end) end |> Enum.map(fn {_, m} -> MapSet.size(m) end) |> Enum.sum() end def part2(data) do grid = data |> String.split("\n", trim: true) |> Enum.map(&String.codepoints/1) |> Enum.map(fn v -> Enum.map(v, &String.to_integer/1) end) values = for {l, i} <- Enum.with_index(grid), {v, j} <- Enum.with_index(l) do {v, {i, j}} end |> Enum.group_by(fn {v, _} -> v end, fn {_, p} -> p end) acc = values |> Map.get(9, []) |> Enum.map(fn p -> {p, 1} end) dist = fn {a, b}, {c, d} -> abs(a-c) + abs(b-d) end count = fn p, prev -> prev |> Enum.filter(fn {p2, _} -> dist.(p, p2) == 1 end) |> Enum.map(fn {_, c} -> c end) |> Enum.sum() end for i <- 8..0//-1, reduce: acc do acc -> Map.get(values, i, []) |> Enum.map(fn p -> {p, count.(p, acc)} end) |> Enum.filter(fn {_, c} -> c > 0 end) end |> Enum.map(fn {_, c} -> c end) |> Enum.sum() end end data = IO.read(:stdio, :eof) {time1 , ans1} = :timer.tc(fn -> Day10.part1(data) end) IO.puts("Time : #{time1 / 1000000}") IO.puts("Answer: #{ans1}") {time2 , ans2} = :timer.tc(fn -> Day10.part2(data) end) IO.puts("Time : #{time2 / 1000000}") IO.puts("Answer: #{ans2}")