part 2, wip

This commit is contained in:
Yanick Champoux 2022-12-25 17:09:27 -05:00
parent bc6b5259c1
commit 1a855600cf
3 changed files with 139 additions and 52 deletions

View File

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

View File

@ -1,4 +1,72 @@
import { bidirectional } from 'graphology-shortest-path';
import * as R from "remeda"; import * as R from "remeda";
import { buildGraph } from './part1.js';
export default () => {}; function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activeSteam = 0) {
//console.log(minutesLeft, activeSteam, locations, possibilities);
if (minutesLeft <= 0) return 0;
if (possibilities.length === 0) return minutesLeft * activeSteam;
const nextToGo = locations.find(([time]) => !time);
for( const l of locations) {
if( l[0] === 0 ) {
activeSteam += l[2];
l[2] = 0;
}
}
let scores = [];
for ( const next of possibilities ) {
const path = bidirectional(graph, nextToGo[1], next);
//console.log(path);
const locs = locations.map( x => x === nextToGo ? [
path.length, next, tunnels[next].flow
] : x );
let time = Math.min( ...locs.map( ([time]) => time ) );
if (time >= minutesLeft) {
scores.push( minutesLeft * activeSteam );
}
else {
//console.log({totalSteam, time, activeSteam});
let ts = time * activeSteam;
scores.push(
ts + finalSteam(
tunnels, graph, minutesLeft - time,
possibilities.filter( x => x !== next ),
locs.map( ([t,dest] ) => [ t -time, dest ]),
activeSteam
)
)
}
}
return Math.max( ...scores );
}
export default (tunnels) => {
const possibilities =
Object.keys(tunnels).filter(
k => tunnels[k].flow
);
const graph = buildGraph(tunnels);
return finalSteam(tunnels, graph, 26, possibilities, [
[ 0, 'AA' ],
[ 0, 'AA' ]
], 0, 0)
};

View File

@ -14,15 +14,20 @@ describe("part 1", () => {
}}) }})
} ) } )
test.only("sample", () => { test("sample", () => {
expectSolution(part1(sample)).toEqual(1651); expect(part1(sample)).toEqual(1651);
}); });
test.todo("solution", () => { test.only("solution", () => {
expectSolution(part1(puzzleInput)).toEqual("TODO"); const r= part1(puzzleInput);
expect(r).toBeGreaterThan(707);
expectSolution(part1(puzzleInput)).toEqual(1871);
}); });
}); });
describe("part 2", () => { describe.only("part 2", () => {
test("sample", () => {
expect(part2(sample)).toEqual(1707);
});
test.todo("solution", () => { test.todo("solution", () => {
expectSolution(part2(puzzleInput)).toEqual("TODO"); expectSolution(part2(puzzleInput)).toEqual("TODO");
}); });