summaryrefslogtreecommitdiffstats
path: root/src/day10.exs
blob: 7530903d696bbc7f414ea5887a915ae3dd19485a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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}")