Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day25

2023/elixir/day25.livemd

Day25

Mix.install([
  {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"},
  {:libgraph, "~> 0.16.0"}
])

Setup

{:ok, data} = KinoAOC.download_puzzle("2023", "25", System.fetch_env!("LB_AOC_SECRET"))

Solve

defmodule Day25 do
  def parse(data) do
    data
    |> String.split("\n", trim: true)
    |> Enum.map(fn row ->
      [h | t] = row |> String.replace(":", "") |> String.split(" ", trim: true)
      {h, t}
    end)
  end

  def solve(data) do
    g = data |> parse() |> to_graph()

    {comp, top3, i} = run_cycle(g)
    [a, b] = Enum.map(comp, &length/1)
    {i, top3, a * b}
  end

  def run_cycle(g) do
    sz = g |> Graph.vertices() |> length()
    max = round(:math.pow(sz, 2) * :math.log(sz))

    Enum.reduce_while(1..max, %{}, fn i, freq ->
      g |> inc_use(freq) |> check_cut(g, i)
    end)
  end

  def get_top3(freq) do
    freq
    |> Enum.sort_by(fn {_, v} -> v end, :desc)
    |> Enum.map(fn {[from, to], _} -> {from, to} end)
    |> Enum.take(3)
  end

  def check_cut(freq, g, i) do
    top3 = get_top3(freq)

    ng = Enum.reduce(top3, g, fn {from, to}, acc ->
      Graph.delete_edge(acc, from, to)
    end)
    comp = Graph.components(ng)

    if length(comp) == 2 do
      {:halt, {comp, top3, i}}
    else
      {:cont, freq}
    end
  end

  # take any random vertices
  # find shortest path
  # increase usage of edges on the path
  def inc_use(g, freq) do
    [from, to] = g |> Graph.vertices() |> Enum.take_random(2)

    Graph.dijkstra(g, from, to)
    |> Enum.chunk_every(2, 1, :discard)
    |> Enum.map(fn pair -> Enum.sort(pair) end)
    |> Enum.reduce(freq, fn pair, freq ->
      Map.update(freq, pair, 1, fn val -> val + 1 end)
    end)
  end

  def to_graph(data) do
    for {from, conn} <- data,
      to <- conn,
      reduce: Graph.new(type: :undirected) do
      g -> Graph.add_edge(g, from, to, weight: 1)
    end
  end
end

t1 =
"""
jqt: rhn xhk nvd
rsh: frs pzl lsr
xhk: hfx
cmg: qnr nvd lhk bvb
rhn: xhk bvb hfx
bvb: xhk hfx
pzl: lsr hfx nvd
qnr: nvd
ntq: jqt hfx bvb xhk
nvd: lhk
lsr: lhk
rzs: qnr cmg lsr rsh
frs: qnr lhk lsr
"""

Day25.solve(t1) |> IO.inspect(label: "t1")
Day25.solve(data) # 591890