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