Powered by AppSignal & Oban Pro

Day 16

2022/day16.livemd

Day 16

Mix.install([
  {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"},
  {:libgraph, github: "hauleth/libgraph", ref: "perf/bellman-ford-implementation"}
])
:ok

Setup

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2022", "16", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
{:ok,
 "Valve QJ has flow rate=11; tunnels lead to valves HB, GL\nValve VZ has flow rate=10; tunnel leads to valve NE\nValve TX has flow rate=19; tunnels lead to valves MG, OQ, HM\nValve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR\nValve IH has flow rate=0; tunnels lead to valves YB, QS\nValve QS has flow rate=22; tunnel leads to valve IH\nValve QB has flow rate=0; tunnels lead to valves QX, ES\nValve NX has flow rate=0; tunnels lead to valves UH, OP\nValve PJ has flow rate=0; tunnels lead to valves OC, UH\nValve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD\nValve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ\nValve UC has flow rate=0; tunnels lead to valves AA, BY\nValve QX has flow rate=0; tunnels lead to valves AA, QB\nValve IZ has flow rate=0; tunnels lead to valves OC, SX\nValve AG has flow rate=13; tunnels lead to valves NW, GL, SM\nValve ON has flow rate=0; tunnels lead to valves MO, ZI\nValve XT has flow rate=18; tunnels lead to valves QZ, PG\nValve AX has flow rate=0; tunnels lead to valves UH, MO\nValve JD has flow rate=0; tunnels lead to valves OR, SM\nValve HM has flow rate=0; tunnels lead to valves TX, QH\nValve LF has flow rate=0; tunnels lead to valves ZI, UH\nValve QH has flow rate=0; tunnels lead to valves OR, HM\nValve RT has flow rate=21; tunnel leads to valve PG\nValve NE has flow rate=0; tunnels lead to valves VZ, TA\nValve OQ has flow rate=0; tunnels lead to valves TX, GE\nValve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH\nValve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF\nValve GE has flow rate=0; tunnels lead to valves YB, OQ\nValve EH has flow rate=0; tunnels lead to valves AA, MO\nValve MG has flow rate=0; tunnels lead to valves TX, NW\nValve YB has flow rate=20; tunnels lead to valves IH, GE, XG\nValve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB\nValve JR has flow rate=0; tunnels lead to valves ZI, OC\nValve GL has flow rate=0; tunnels lead to valves AG, QJ\nValve SM has flow rate=0; tunnels lead to valves JD, AG\nValve HB has flow rate=0; tunnels lead to valves OR, QJ\nValve TA has flow rate=0; tunnels lead to valves OC, NE\nValve PG has flow rate=0; tunnels lead to valves RT, XT\nValve XG has flow rate=0; tunnels lead to valves CB, YB\nValve ES has flow rate=9; tunnels lead to valves QB, FL\nValve BH has flow rate=0; tunnels lead to valves RU, OR\nValve FL has flow rate=0; tunnels lead to valves SX, ES\nValve CB has flow rate=0; tunnels lead to valves MO, XG\nValve QZ has flow rate=0; tunnels lead to valves AA, XT\nValve BY has flow rate=0; tunnels lead to valves UC, ZI\nValve ZH has flow rate=0; tunnels lead to valves MO, OC\nValve OP has flow rate=0; tunnels lead to valves NX, AA\nValve NW has flow rate=0; tunnels lead to valves MG, AG\nValve RU has flow rate=0; tunnels lead to valves ZI, BH\nValve SX has flow rate=16; tunnels lead to valves IZ, FL"}
# puzzle_input = """
# Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
# Valve BB has flow rate=13; tunnels lead to valves CC, AA
# Valve CC has flow rate=2; tunnels lead to valves DD, BB
# Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
# Valve EE has flow rate=3; tunnels lead to valves FF, DD
# Valve FF has flow rate=0; tunnels lead to valves EE, GG
# Valve GG has flow rate=0; tunnels lead to valves FF, HH
# Valve HH has flow rate=22; tunnel leads to valve GG
# Valve II has flow rate=0; tunnels lead to valves AA, JJ
# Valve JJ has flow rate=21; tunnel leads to valve II
# """
nil
{{start, _}, valves} =
  valves =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Kino.render()
  |> Enum.map(fn line ->
    %{
      "name" => name,
      "rate" => rate,
      "routes" => routes
    } =
      Regex.named_captures(
        ~r/Valve (?<name>..).*rate=(?<rate>\d+);.*valves? (?<routes>.*)$/,
        line
      )

    {name, %{rate: String.to_integer(rate), routes: String.split(routes, ~r/,\s*/, trim: true)}}
  end)
  |> then(&{hd(&1), Map.new(&1)})
["Valve QJ has flow rate=11; tunnels lead to valves HB, GL",
 "Valve VZ has flow rate=10; tunnel leads to valve NE",
 "Valve TX has flow rate=19; tunnels lead to valves MG, OQ, HM",
 "Valve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR",
 "Valve IH has flow rate=0; tunnels lead to valves YB, QS",
 "Valve QS has flow rate=22; tunnel leads to valve IH",
 "Valve QB has flow rate=0; tunnels lead to valves QX, ES",
 "Valve NX has flow rate=0; tunnels lead to valves UH, OP",
 "Valve PJ has flow rate=0; tunnels lead to valves OC, UH",
 "Valve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD",
 "Valve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ",
 "Valve UC has flow rate=0; tunnels lead to valves AA, BY",
 "Valve QX has flow rate=0; tunnels lead to valves AA, QB",
 "Valve IZ has flow rate=0; tunnels lead to valves OC, SX",
 "Valve AG has flow rate=13; tunnels lead to valves NW, GL, SM",
 "Valve ON has flow rate=0; tunnels lead to valves MO, ZI",
 "Valve XT has flow rate=18; tunnels lead to valves QZ, PG",
 "Valve AX has flow rate=0; tunnels lead to valves UH, MO",
 "Valve JD has flow rate=0; tunnels lead to valves OR, SM",
 "Valve HM has flow rate=0; tunnels lead to valves TX, QH",
 "Valve LF has flow rate=0; tunnels lead to valves ZI, UH",
 "Valve QH has flow rate=0; tunnels lead to valves OR, HM",
 "Valve RT has flow rate=21; tunnel leads to valve PG",
 "Valve NE has flow rate=0; tunnels lead to valves VZ, TA",
 "Valve OQ has flow rate=0; tunnels lead to valves TX, GE",
 "Valve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH",
 "Valve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF",
 "Valve GE has flow rate=0; tunnels lead to valves YB, OQ",
 "Valve EH has flow rate=0; tunnels lead to valves AA, MO",
 "Valve MG has flow rate=0; tunnels lead to valves TX, NW",
 "Valve YB has flow rate=20; tunnels lead to valves IH, GE, XG",
 "Valve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB",
 "Valve JR has flow rate=0; tunnels lead to valves ZI, OC",
 "Valve GL has flow rate=0; tunnels lead to valves AG, QJ",
 "Valve SM has flow rate=0; tunnels lead to valves JD, AG",
 "Valve HB has flow rate=0; tunnels lead to valves OR, QJ",
 "Valve TA has flow rate=0; tunnels lead to valves OC, NE",
 "Valve PG has flow rate=0; tunnels lead to valves RT, XT",
 "Valve XG has flow rate=0; tunnels lead to valves CB, YB",
 "Valve ES has flow rate=9; tunnels lead to valves QB, FL",
 "Valve BH has flow rate=0; tunnels lead to valves RU, OR",
 "Valve FL has flow rate=0; tunnels lead to valves SX, ES",
 "Valve CB has flow rate=0; tunnels lead to valves MO, XG",
 "Valve QZ has flow rate=0; tunnels lead to valves AA, XT",
 "Valve BY has flow rate=0; tunnels lead to valves UC, ZI",
 "Valve ZH has flow rate=0; tunnels lead to valves MO, OC",
 "Valve OP has flow rate=0; tunnels lead to valves NX, AA",
 "Valve NW has flow rate=0; tunnels lead to valves MG, AG",
 "Valve RU has flow rate=0; tunnels lead to valves ZI, BH",
 "Valve SX has flow rate=16; tunnels lead to valves IZ, FL"]
{{"QJ", %{rate: 11, routes: ["HB", "GL"]}},
 %{
   "CB" => %{rate: 0, routes: ["MO", "XG"]},
   "EH" => %{rate: 0, routes: ["AA", "MO"]},
   "YB" => %{rate: 20, routes: ["IH", "GE", "XG"]},
   "ON" => %{rate: 0, routes: ["MO", "ZI"]},
   "ES" => %{rate: 9, routes: ["QB", "FL"]},
   "XG" => %{rate: 0, routes: ["CB", "YB"]},
   "TX" => %{rate: 19, routes: ["MG", "OQ", "HM"]},
   "RT" => %{rate: 21, routes: ["PG"]},
   "GL" => %{rate: 0, routes: ["AG", "QJ"]},
   "XT" => %{rate: 18, routes: ["QZ", "PG"]},
   "BY" => %{rate: 0, routes: ["UC", "ZI"]},
   "QJ" => %{rate: 11, routes: ["HB", "GL"]},
   "QB" => %{rate: 0, routes: ["QX", "ES"]},
   "QH" => %{rate: 0, routes: ["OR", "HM"]},
   "SX" => %{rate: 16, routes: ["IZ", "FL"]},
   "ZI" => %{rate: 5, routes: ["BY", "ON", "RU", "LF", "JR"]},
   "OC" => %{rate: 7, routes: ["IZ", "JR", "TA", "ZH", "PJ"]},
   "NW" => %{rate: 0, routes: ["MG", "AG"]},
   "UH" => %{rate: 17, routes: ["PJ", "NX", "AX", "LF"]},
   "VZ" => %{rate: 10, routes: ["NE"]},
   "MO" => %{rate: 15, routes: ["EH", "ON", "AX", "ZH", "CB"]},
   "ZH" => %{rate: 0, routes: ["MO", "OC"]},
   "RU" => %{rate: 0, routes: ["ZI", "BH"]},
   "FL" => %{rate: 0, routes: ["SX", "ES"]},
   "SM" => %{rate: 0, routes: ["JD", "AG"]},
   "AA" => %{rate: 0, routes: ["QZ", "UC", "OP", "QX", "EH"]},
   "JR" => %{rate: 0, routes: ["ZI", "OC"]},
   "QS" => %{rate: 22, routes: ["IH"]},
   "AG" => %{rate: 13, routes: ["NW", "GL", "SM"]},
   "JD" => %{rate: 0, routes: ["OR", "SM"]},
   "QZ" => %{rate: 0, routes: ["AA", "XT"]},
   "MG" => %{rate: 0, routes: ["TX", "NW"]},
   "UC" => %{rate: 0, routes: ["AA", "BY"]},
   "AX" => %{rate: 0, routes: ["UH", "MO"]},
   "HM" => %{rate: 0, routes: ["TX", "QH"]},
   "LF" => %{rate: 0, routes: ["ZI", "UH"]},
   "BH" => %{rate: 0, routes: ["RU", "OR"]},
   "OR" => %{rate: 6, routes: ["QH", "BH", "HB", "JD"]},
   "GE" => %{rate: 0, routes: ["YB", "OQ"]},
   "QX" => %{rate: 0, routes: ["AA", "QB"]},
   "IZ" => %{rate: 0, routes: ["OC", "SX"]},
   "PG" => %{rate: 0, routes: ["RT", "XT"]},
   "NX" => %{rate: 0, routes: ["UH", "OP"]},
   "OP" => %{rate: 0, routes: ["NX", "AA"]},
   "TA" => %{rate: 0, routes: ["OC", ...]},
   "IH" => %{rate: 0, routes: [...]},
   "HB" => %{rate: 0, ...},
   "PJ" => %{...},
   ...
 }}
graph = Graph.new(type: :directed)

edges =
  Enum.flat_map(valves, fn {a, %{routes: routes}} ->
    for b <- routes, p <- [{a, b, weight: 1}, {b, a, weight: 1}], do: p
  end)

graph =
  Graph.add_edges(graph, edges)
  |> Kino.render()

paths =
  for v <- Graph.vertices(graph), into: %{} do
    routes =
      graph
      |> Graph.bellman_ford(v)
      |> Enum.filter(fn {k, _} -> valves[k].rate > 0 and k != v end)
      |> Map.new()

    {v, routes}
  end
#Graph<type: directed, vertices: ["LF", "CB", "AX", "ZI", "ZH", "VZ", "AA", "UH", "OC", "IH", "FL",
 "JR", "QB", "EH", "QH", "ON", "TA", "PJ", "SX", "YB", "UC", "BH", "MO", "OQ", "HM", "JD", "OR",
 "NE", "QS", "XT", "IZ", "QZ", "BY", "PG", "NW", "HB", "AG", "QJ", "RT", "TX", "GE", "QX", "XG",
 "NX", "GL", "RU", "SM", "ES", "MG",
 "OP"], edges: ["LF" -> "UH", "LF" -> "ZI", "CB" -> "MO", "CB" -> "XG", "AX" -> "UH", "AX" -> "MO", "ZI" -> "BY", "ZI" -> "RU", "ZI" -> "ON", "ZI" -> "LF", "ZI" -> "JR", "ZH" -> "OC", "ZH" -> "MO", "VZ" -> "NE", "AA" -> "UC", "AA" -> "EH", "AA" -> "QX", "AA" -> "OP", "AA" -> "QZ", "UH" -> "LF", "UH" -> "PJ", "UH" -> "AX", "UH" -> "NX", "OC" -> "ZH", "OC" -> "IZ", "OC" -> "TA", "OC" -> "PJ", "OC" -> "JR", "IH" -> "YB", "IH" -> "QS", "FL" -> "SX", "FL" -> "ES", "JR" -> "OC", "JR" -> "ZI", "QB" -> "QX", "QB" -> "ES", "EH" -> "MO", "EH" -> "AA", "QH" -> "OR", "QH" -> "HM", "ON" -> "MO", "ON" -> "ZI", "TA" -> "OC", "TA" -> "NE", "PJ" -> "OC", "PJ" -> "UH", "SX" -> "IZ", "SX" -> "FL", "YB" -> "GE", "YB" -> "IH", "YB" -> "XG", "UC" -> "BY", "UC" -> "AA", "BH" -> "OR", "BH" -> "RU", "MO" -> "ZH", "MO" -> "EH", "MO" -> "ON", "MO" -> "CB", "MO" -> "AX", "OQ" -> "GE", "OQ" -> "TX", "HM" -> "TX", "HM" -> "QH", "JD" -> "OR", "JD" -> "SM", "OR" -> "BH", "OR" -> "HB", "OR" -> "JD", "OR" -> "QH", "NE" -> "TA", "NE" -> "VZ", "QS" -> "IH", "XT" -> "QZ", "XT" -> "PG", "IZ" -> "OC", "IZ" -> "SX", "QZ" -> "AA", "QZ" -> "XT", "BY" -> "UC", "BY" -> "ZI", "PG" -> "RT", "PG" -> "XT", "NW" -> "MG", "NW" -> "AG", "HB" -> "OR", "HB" -> "QJ", "AG" -> "SM", "AG" -> "GL", "AG" -> "NW", "QJ" -> "GL", "QJ" -> "HB", "RT" -> "PG", "TX" -> "OQ", "TX" -> "MG", "TX" -> "HM", "GE" -> "OQ", "GE" -> "YB", "QX" -> "QB", "QX" -> "AA", "XG" -> "YB", "XG" -> "CB", "NX" -> "UH", "NX" -> "OP", "GL" -> "QJ", "GL" -> "AG", "RU" -> "BH", "RU" -> "ZI", "SM" -> "AG", "SM" -> "JD", "ES" -> "QB", "ES" -> "FL", "MG" -> "NW", "MG" -> "TX", "OP" -> "AA", "OP" -> "NX"]>
%{
  "CB" => %{
    "AG" => 8,
    "ES" => 6,
    "MO" => 1,
    "OC" => 3,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 4,
    "RT" => 7,
    "SX" => 5,
    "TX" => 5,
    "UH" => 3,
    "VZ" => 6,
    "XT" => 5,
    "YB" => 2,
    "ZI" => 3
  },
  "EH" => %{
    "AG" => 9,
    "ES" => 4,
    "MO" => 1,
    "OC" => 3,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 6,
    "RT" => 5,
    "SX" => 5,
    "TX" => 7,
    "UH" => 3,
    "VZ" => 6,
    "XT" => 3,
    "YB" => 4,
    "ZI" => 3
  },
  "YB" => %{
    "AG" => 6,
    "ES" => 8,
    "MO" => 3,
    "OC" => 5,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 2,
    "RT" => 9,
    "SX" => 7,
    "TX" => 3,
    "UH" => 5,
    "VZ" => 8,
    "XT" => 7,
    "ZI" => 5
  },
  "ON" => %{
    "AG" => 7,
    "ES" => 6,
    "MO" => 1,
    "OC" => 3,
    "OR" => 4,
    "QJ" => 6,
    "QS" => 6,
    "RT" => 7,
    "SX" => 5,
    "TX" => 7,
    "UH" => 3,
    "VZ" => 6,
    "XT" => 5,
    "YB" => 4,
    "ZI" => 1
  },
  "ES" => %{
    "AG" => 12,
    "MO" => 5,
    "OC" => 4,
    "OR" => 9,
    "QJ" => 11,
    "QS" => 10,
    "RT" => 7,
    "SX" => 2,
    "TX" => 11,
    "UH" => 6,
    "VZ" => 7,
    "XT" => 5,
    "YB" => 8,
    "ZI" => 6
  },
  "XG" => %{
    "AG" => 7,
    "ES" => 7,
    "MO" => 2,
    "OC" => 4,
    "OR" => 7,
    "QJ" => 9,
    "QS" => 3,
    "RT" => 8,
    "SX" => 6,
    "TX" => 4,
    "UH" => 4,
    "VZ" => 7,
    "XT" => 6,
    "YB" => 1,
    "ZI" => 4
  },
  "TX" => %{
    "AG" => 3,
    "ES" => 11,
    "MO" => 6,
    "OC" => 8,
    "OR" => 3,
    "QJ" => 5,
    "QS" => 5,
    "RT" => 12,
    "SX" => 10,
    "UH" => 8,
    "VZ" => 11,
    "XT" => 10,
    "YB" => 3,
    "ZI" => 6
  },
  "RT" => %{
    "AG" => 13,
    "ES" => 7,
    "MO" => 6,
    "OC" => 8,
    "OR" => 10,
    "QJ" => 12,
    "QS" => 11,
    "SX" => 9,
    "TX" => 12,
    "UH" => 7,
    "VZ" => 11,
    "XT" => 2,
    "YB" => 9,
    "ZI" => 7
  },
  "GL" => %{
    "AG" => 1,
    "ES" => 12,
    "MO" => 8,
    "OC" => 8,
    "OR" => 3,
    "QJ" => 1,
    "QS" => 9,
    "RT" => 13,
    "SX" => 10,
    "TX" => 4,
    "UH" => 8,
    "VZ" => 11,
    "XT" => 11,
    "YB" => 7,
    "ZI" => 6
  },
  "XT" => %{
    "AG" => 11,
    "ES" => 5,
    "MO" => 4,
    "OC" => 6,
    "OR" => 8,
    "QJ" => 10,
    "QS" => 9,
    "RT" => 2,
    "SX" => 7,
    "TX" => 10,
    "UH" => 5,
    "VZ" => 9,
    "YB" => 7,
    "ZI" => 5
  },
  "BY" => %{
    "AG" => 7,
    "ES" => 5,
    "MO" => 3,
    "OC" => 3,
    "OR" => 4,
    "QJ" => 6,
    "QS" => 8,
    "RT" => 6,
    "SX" => 5,
    "TX" => 7,
    "UH" => 3,
    "VZ" => 6,
    "XT" => 4,
    "YB" => 6,
    "ZI" => 1
  },
  "QJ" => %{
    "AG" => 2,
    "ES" => 11,
    "MO" => 7,
    "OC" => 7,
    "OR" => 2,
    "QS" => 10,
    "RT" => 12,
    "SX" => 9,
    "TX" => 5,
    "UH" => 7,
    "VZ" => 10,
    "XT" => 10,
    "YB" => 8,
    "ZI" => 5
  },
  "QB" => %{
    "AG" => 11,
    "ES" => 1,
    "MO" => 4,
    "OC" => 5,
    "OR" => 8,
    "QJ" => 10,
    "QS" => 9,
    "RT" => 6,
    "SX" => 3,
    "TX" => 10,
    "UH" => 5,
    "VZ" => 8,
    "XT" => 4,
    "YB" => 7,
    "ZI" => 5
  },
  "QH" => %{
    "AG" => 4,
    "ES" => 10,
    "MO" => 6,
    "OC" => 6,
    "OR" => 1,
    "QJ" => 3,
    "QS" => 7,
    "RT" => 11,
    "SX" => 8,
    "TX" => 2,
    "UH" => 6,
    "VZ" => 9,
    "XT" => 9,
    "YB" => 5,
    "ZI" => 4
  },
  "SX" => %{
    "AG" => 10,
    "ES" => 2,
    "MO" => 4,
    "OC" => 2,
    "OR" => 7,
    "QJ" => 9,
    "QS" => 9,
    "RT" => 9,
    "TX" => 10,
    "UH" => 4,
    "VZ" => 5,
    "XT" => 7,
    "YB" => 7,
    "ZI" => 4
  },
  "ZI" => %{
    "AG" => 6,
    "ES" => 6,
    "MO" => 2,
    "OC" => 2,
    "OR" => 3,
    "QJ" => 5,
    "QS" => 7,
    "RT" => 7,
    "SX" => 4,
    "TX" => 6,
    "UH" => 2,
    "VZ" => 5,
    "XT" => 5,
    "YB" => 5
  },
  "OC" => %{
    "AG" => 8,
    "ES" => 4,
    "MO" => 2,
    "OR" => 5,
    "QJ" => 7,
    "QS" => 7,
    "RT" => 8,
    "SX" => 2,
    "TX" => 8,
    "UH" => 2,
    "VZ" => 3,
    "XT" => 6,
    "YB" => 5,
    "ZI" => 2
  },
  "NW" => %{
    "AG" => 1,
    "ES" => 13,
    "MO" => 8,
    "OC" => 9,
    "OR" => 4,
    "QJ" => 3,
    "QS" => 7,
    "RT" => 14,
    "SX" => 11,
    "TX" => 2,
    "UH" => 9,
    "VZ" => 12,
    "XT" => 12,
    "YB" => 5,
    "ZI" => 7
  },
  "UH" => %{
    "AG" => 8,
    "ES" => 6,
    "MO" => 2,
    "OC" => 2,
    "OR" => 5,
    "QJ" => 7,
    "QS" => 7,
    "RT" => 7,
    "SX" => 4,
    "TX" => 8,
    "VZ" => 5,
    "XT" => 5,
    "YB" => 5,
    "ZI" => 2
  },
  "VZ" => %{
    "AG" => 11,
    "ES" => 7,
    "MO" => 5,
    "OC" => 3,
    "OR" => 8,
    "QJ" => 10,
    "QS" => 10,
    "RT" => 11,
    "SX" => 5,
    "TX" => 11,
    "UH" => 5,
    "XT" => 9,
    "YB" => 8,
    "ZI" => 5
  },
  "MO" => %{
    "AG" => 8,
    "ES" => 5,
    "OC" => 2,
    "OR" => 5,
    "QJ" => 7,
    "QS" => 5,
    "RT" => 6,
    "SX" => 4,
    "TX" => 6,
    "UH" => 2,
    "VZ" => 5,
    "XT" => 4,
    "YB" => 3,
    "ZI" => 2
  },
  "ZH" => %{
    "AG" => 9,
    "ES" => 5,
    "MO" => 1,
    "OC" => 1,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 6,
    "RT" => 7,
    "SX" => 3,
    "TX" => 7,
    "UH" => 3,
    "VZ" => 4,
    "XT" => 5,
    "YB" => 4,
    "ZI" => 3
  },
  "RU" => %{
    "AG" => 5,
    "ES" => 7,
    "MO" => 3,
    "OC" => 3,
    "OR" => 2,
    "QJ" => 4,
    "QS" => 8,
    "RT" => 8,
    "SX" => 5,
    "TX" => 5,
    "UH" => 3,
    "VZ" => 6,
    "XT" => 6,
    "YB" => 6,
    "ZI" => 1
  },
  "FL" => %{
    "AG" => 11,
    "ES" => 1,
    "MO" => 5,
    "OC" => 3,
    "OR" => 8,
    "QJ" => 10,
    "QS" => 10,
    "RT" => 8,
    "SX" => 1,
    "TX" => 11,
    "UH" => 5,
    "VZ" => 6,
    "XT" => 6,
    "YB" => 8,
    "ZI" => 5
  },
  "SM" => %{
    "AG" => 1,
    "ES" => 11,
    "MO" => 7,
    "OC" => 7,
    "OR" => 2,
    "QJ" => 3,
    "QS" => 9,
    "RT" => 12,
    "SX" => 9,
    "TX" => 4,
    "UH" => 7,
    "VZ" => 10,
    "XT" => 10,
    "YB" => 7,
    "ZI" => 5
  },
  "AA" => %{
    "AG" => 9,
    "ES" => 3,
    "MO" => 2,
    "OC" => 4,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 7,
    "RT" => 4,
    "SX" => 5,
    "TX" => 8,
    "UH" => 3,
    "VZ" => 7,
    "XT" => 2,
    "YB" => 5,
    "ZI" => 3
  },
  "JR" => %{
    "AG" => 7,
    "ES" => 5,
    "MO" => 3,
    "OC" => 1,
    "OR" => 4,
    "QJ" => 6,
    "QS" => 8,
    "RT" => 8,
    "SX" => 3,
    "TX" => 7,
    "UH" => 3,
    "VZ" => 4,
    "XT" => 6,
    "YB" => 6,
    "ZI" => 1
  },
  "QS" => %{
    "AG" => 8,
    "ES" => 10,
    "MO" => 5,
    "OC" => 7,
    "OR" => 8,
    "QJ" => 10,
    "RT" => 11,
    "SX" => 9,
    "TX" => 5,
    "UH" => 7,
    "VZ" => 10,
    "XT" => 9,
    "YB" => 2,
    "ZI" => 7
  },
  "AG" => %{
    "ES" => 12,
    "MO" => 8,
    "OC" => 8,
    "OR" => 3,
    "QJ" => 2,
    "QS" => 8,
    "RT" => 13,
    "SX" => 10,
    "TX" => 3,
    "UH" => 8,
    "VZ" => 11,
    "XT" => 11,
    "YB" => 6,
    "ZI" => 6
  },
  "JD" => %{
    "AG" => 2,
    "ES" => 10,
    "MO" => 6,
    "OC" => 6,
    "OR" => 1,
    "QJ" => 3,
    "QS" => 9,
    "RT" => 11,
    "SX" => 8,
    "TX" => 4,
    "UH" => 6,
    "VZ" => 9,
    "XT" => 9,
    "YB" => 7,
    "ZI" => 4
  },
  "QZ" => %{
    "AG" => 10,
    "ES" => 4,
    "MO" => 3,
    "OC" => 5,
    "OR" => 7,
    "QJ" => 9,
    "QS" => 8,
    "RT" => 3,
    "SX" => 6,
    "TX" => 9,
    "UH" => 4,
    "VZ" => 8,
    "XT" => 1,
    "YB" => 6,
    "ZI" => 4
  },
  "MG" => %{
    "AG" => 2,
    "ES" => 12,
    "MO" => 7,
    "OC" => 9,
    "OR" => 4,
    "QJ" => 4,
    "QS" => 6,
    "RT" => 13,
    "SX" => 11,
    "TX" => 1,
    "UH" => 9,
    "VZ" => 12,
    "XT" => 11,
    "YB" => 4,
    "ZI" => 7
  },
  "UC" => %{
    "AG" => 8,
    "ES" => 4,
    "MO" => 3,
    "OC" => 4,
    "OR" => 5,
    "QJ" => 7,
    "QS" => 8,
    "RT" => 5,
    "SX" => 6,
    "TX" => 8,
    "UH" => 4,
    "VZ" => 7,
    "XT" => 3,
    "YB" => 6,
    "ZI" => 2
  },
  "AX" => %{
    "AG" => 9,
    "ES" => 6,
    "MO" => 1,
    "OC" => 3,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 6,
    "RT" => 7,
    "SX" => 5,
    "TX" => 7,
    "UH" => 1,
    "VZ" => 6,
    "XT" => 5,
    "YB" => 4,
    "ZI" => 3
  },
  "HM" => %{
    "AG" => 4,
    "ES" => 11,
    "MO" => 7,
    "OC" => 7,
    "OR" => 2,
    "QJ" => 4,
    "QS" => 6,
    "RT" => 12,
    "SX" => 9,
    "TX" => 1,
    "UH" => 7,
    "VZ" => 10,
    "XT" => 10,
    "YB" => 4,
    "ZI" => 5
  },
  "LF" => %{
    "AG" => 7,
    "ES" => 7,
    "MO" => 3,
    "OC" => 3,
    "OR" => 4,
    "QJ" => 6,
    "QS" => 8,
    "RT" => 8,
    "SX" => 5,
    "TX" => 7,
    "UH" => 1,
    "VZ" => 6,
    "XT" => 6,
    "YB" => 6,
    ...
  },
  "BH" => %{
    "AG" => 4,
    "ES" => 8,
    "MO" => 4,
    "OC" => 4,
    "OR" => 1,
    "QJ" => 3,
    "QS" => 9,
    "RT" => 9,
    "SX" => 6,
    "TX" => 4,
    "UH" => 4,
    "VZ" => 7,
    "XT" => 7,
    ...
  },
  "OR" => %{
    "AG" => 3,
    "ES" => 9,
    "MO" => 5,
    "OC" => 5,
    "QJ" => 2,
    "QS" => 8,
    "RT" => 10,
    "SX" => 7,
    "TX" => 3,
    "UH" => 5,
    "VZ" => 8,
    "XT" => 8,
    ...
  },
  "GE" => %{
    "AG" => 5,
    "ES" => 9,
    "MO" => 4,
    "OC" => 6,
    "OR" => 5,
    "QJ" => 7,
    "QS" => 3,
    "RT" => 10,
    "SX" => 8,
    "TX" => 2,
    "UH" => 6,
    ...
  },
  "QX" => %{
    "AG" => 10,
    "ES" => 2,
    "MO" => 3,
    "OC" => 5,
    "OR" => 7,
    "QJ" => 9,
    "QS" => 8,
    "RT" => 5,
    "SX" => 4,
    "TX" => 9,
    ...
  },
  "IZ" => %{
    "AG" => 9,
    "ES" => 3,
    "MO" => 3,
    "OC" => 1,
    "OR" => 6,
    "QJ" => 8,
    "QS" => 8,
    "RT" => 9,
    "SX" => 1,
    ...
  },
  "PG" => %{
    "AG" => 12,
    "ES" => 6,
    "MO" => 5,
    "OC" => 7,
    "OR" => 9,
    "QJ" => 11,
    "QS" => 10,
    "RT" => 1,
    ...
  },
  "NX" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 3, "OR" => 6, "QJ" => 8, "QS" => 8, ...},
  "OP" => %{"AG" => 10, "ES" => 4, "MO" => 3, "OC" => 4, "OR" => 7, "QJ" => 9, ...},
  "TA" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 1, "OR" => 6, ...},
  "IH" => %{"AG" => 7, "ES" => 9, "MO" => 4, "OC" => 6, ...},
  "HB" => %{"AG" => 3, "ES" => 10, "MO" => 6, ...},
  "PJ" => %{"AG" => 9, "ES" => 5, ...},
  "OQ" => %{"AG" => 4, ...},
  "NE" => %{...}
}

Task 1

defmodule Alone do
  def visit(current, valves, paths, left, opened) when left >= 0 do
    {left, rate, opened} =
      case valves[current].rate do
        0 -> {left, 0, opened}
        other -> {left - 1, other, Map.put(opened, current, left - 1)}
      end

    rate = rate * left

    paths[current]
    |> Enum.map(fn
      {next, weight} when weight + 1 < left and not is_map_key(opened, next) ->
        {val, opened} = visit(next, valves, paths, left - weight, opened)
        {val + rate, opened}

      _ ->
        {rate, opened}
    end)
    |> Enum.max_by(&elem(&1, 0))
  end
end
{:module, Valves, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:visit, 5}}
{t, v} = Alone.visit("AA", valves, paths, 30, %{})
{1820, %{"AG" => 6, "MO" => 23, "QJ" => 3, "QS" => 16, "TX" => 10, "UH" => 26, "YB" => 19}}

Task 2

defmodule Alone do
  def visit(current, valves, paths, left, opened) when left >= 0 do
    {left, rate, opened} =
      case valves[current].rate do
        0 -> {left, 0, opened}
        other -> {left - 1, other, Map.put(opened, current, left - 1)}
      end

    rate = rate * left

    paths[current]
    |> Enum.map(fn
      {next, weight} when weight + 1 < left and not is_map_key(opened, next) ->
        {val, opened} = visit(next, valves, paths, left - weight, opened)
        {val + rate, opened}

      _ ->
        {rate, opened}
    end)
    |> Enum.max_by(&elem(&1, 0))
  end
end