|
| 1 | +defmodule Day25 do |
| 2 | + def read_input(file_path) do |
| 3 | + file_path |
| 4 | + |> File.read!() |
| 5 | + |> String.split("\n", trim: true) |
| 6 | + |> Enum.map(&parse_line/1) |
| 7 | + |> add_to_graph() |
| 8 | + end |
| 9 | + |
| 10 | + def parse_line(line) do |
| 11 | + [from | rest] = line |> String.split(~r/\ |:/, trim: true) |
| 12 | + {from, rest} |
| 13 | + end |
| 14 | + |
| 15 | + def add_to_graph(l), do: add_to_graph(l, Map.new()) |
| 16 | + def add_to_graph([], graph), do: graph |
| 17 | + |
| 18 | + def add_to_graph([{from, tos} | rest], graph) do |
| 19 | + ng = Map.update(graph, from, tos, fn l -> l ++ tos end) |
| 20 | + |
| 21 | + add_to_graph( |
| 22 | + rest, |
| 23 | + tos |> Enum.reduce(ng, fn t, g -> Map.update(g, t, [from], fn l -> [from | l] end) end) |
| 24 | + ) |
| 25 | + end |
| 26 | + |
| 27 | + def reach(graph, set) do |
| 28 | + Enum.reduce(set, MapSet.new(), fn k, acc -> MapSet.new(graph[k]) |> MapSet.union(acc) end) |
| 29 | + |> MapSet.reject(&MapSet.member?(set, &1)) |
| 30 | + end |
| 31 | + |
| 32 | + def number_of_outer_connections(graph, set) do |
| 33 | + r = reach(graph, set) |
| 34 | + |
| 35 | + Enum.reduce(r, 0, fn v, acc -> |
| 36 | + (graph[v] |> Enum.filter(&MapSet.member?(set, &1)) |> length()) + acc |
| 37 | + end) |
| 38 | + end |
| 39 | + |
| 40 | + def put_vertex(graph, {vs, es}, v) do |
| 41 | + new_es = |
| 42 | + ((es |> Enum.reject(fn {_, t} -> t == v end)) ++ |
| 43 | + (graph[v] |> Enum.reject(&MapSet.member?(vs, &1)) |> Enum.map(&{v, &1}))) |
| 44 | + |> MapSet.new() |
| 45 | + |
| 46 | + new_vs = MapSet.put(vs, v) |
| 47 | + |
| 48 | + {new_vs, new_es} |
| 49 | + end |
| 50 | + |
| 51 | + def solve(graph) do |
| 52 | + first = graph |> Enum.at(0) |> elem(0) |
| 53 | + first_con = graph[first] |
| 54 | + initial_edges = first_con |> Enum.map(&{first, &1}) |> MapSet.new() |
| 55 | + |
| 56 | + solve( |
| 57 | + graph, |
| 58 | + [{MapSet.new([first]), initial_edges}], |
| 59 | + MapSet.new() |
| 60 | + ) |
| 61 | + end |
| 62 | + |
| 63 | + def solve(graph, [{v, e} | sets], seen) do |
| 64 | + new_seen = seen |> MapSet.put(v) |
| 65 | + |
| 66 | + case MapSet.size(e) do |
| 67 | + 3 -> |
| 68 | + (map_size(graph) - MapSet.size(v)) * MapSet.size(v) |
| 69 | + |
| 70 | + _ -> |
| 71 | + r = e |> Enum.map(&elem(&1, 1)) |> Enum.dedup() |
| 72 | + |
| 73 | + new_s = |
| 74 | + r |
| 75 | + |> Enum.map(&put_vertex(graph, {v, e}, &1)) |
| 76 | + |> Enum.reject(&MapSet.member?(new_seen, elem(&1, 0))) |
| 77 | + |> Enum.sort_by(&MapSet.size(MapSet.difference(elem(&1, 1), e))) |
| 78 | + |
| 79 | + solve(graph, new_s ++ sets, new_seen) |
| 80 | + end |
| 81 | + end |
| 82 | + |
| 83 | + def partA(file_path) do |
| 84 | + file_path |> read_input() |> solve() |
| 85 | + end |
| 86 | +end |
0 commit comments