import * as R from "remeda"; import u from "updeep"; import Graph from 'graphology'; import { bidirectional } from 'graphology-shortest-path'; import { combinations, permutations } from "combinatorial-generators"; import { readFile } from "../05/part1.js"; const parseLine = (line) => { const { groups } = line.match(/Valve (?..).*flow rate=(?\d+).*valves? (?.*)/); return [groups.valve, { exits: groups.exits.split(',').map(x => x.trim()), flow: parseInt(groups.flow) }] } const readInput = (...args) => R.pipe( readFile(...args), (lines) => lines.split("\n"), R.compact, // remove last line R.map(parseLine), Object.fromEntries, ); export const puzzleInput = readInput(import.meta.url, "input"); export const sample = readInput(import.meta.url, "sample"); function finalSteam(tunnels, graph, minutesLeft, possibilities, location = 'AA', activeSteam = 0) { //console.log(minutesLeft, totalSteam, itinary); if (minutesLeft <= 0) return 0; if (possibilities.length === 0) return minutesLeft * activeSteam; let scores = []; for ( const next of possibilities ) { const path = bidirectional(graph, location, next); //console.log(path); let time = path.length; if (time >= minutesLeft) { scores.push( minutesLeft * activeSteam ); } else { //console.log({totalSteam, time, activeSteam}); let ts = time * activeSteam; let as = activeSteam + tunnels[next].flow; scores.push( ts + finalSteam( tunnels, graph, minutesLeft - time, possibilities.filter( x => x !== next ), next, as ) ) } } return Math.max( ...scores ); } export const buildGraph = tunnels => { const graph = new Graph(); Object.keys(tunnels).forEach(x => graph.addNode(x)); Object.entries(tunnels).forEach(([location, { exits }]) => { exits.forEach(exit => graph.addEdge(location, exit)); }); return graph; }; export default (tunnels) => { const possibilities = Object.keys(tunnels).filter( k => tunnels[k].flow ); const graph = buildGraph(tunnels); return finalSteam(tunnels, graph, 30, possibilities, 'AA', 0, 0) };