Day 16
This commit is contained in:
parent
7dd504945c
commit
d0e924934e
52
16/input
Normal file
52
16/input
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Valve AP has flow rate=0; tunnels lead to valves AA, ON
|
||||||
|
Valve QN has flow rate=21; tunnels lead to valves RI, CG
|
||||||
|
Valve LK has flow rate=0; tunnels lead to valves XM, AA
|
||||||
|
Valve HA has flow rate=0; tunnels lead to valves WH, KF
|
||||||
|
Valve DS has flow rate=16; tunnel leads to valve II
|
||||||
|
Valve KD has flow rate=0; tunnels lead to valves KG, QB
|
||||||
|
Valve JW has flow rate=0; tunnels lead to valves AD, KF
|
||||||
|
Valve HU has flow rate=0; tunnels lead to valves UK, CO
|
||||||
|
Valve AE has flow rate=10; tunnels lead to valves IR, PT, UV
|
||||||
|
Valve XA has flow rate=0; tunnels lead to valves CG, EU
|
||||||
|
Valve SE has flow rate=17; tunnels lead to valves YR, AD
|
||||||
|
Valve TR has flow rate=0; tunnels lead to valves AL, CS
|
||||||
|
Valve BS has flow rate=0; tunnels lead to valves YH, XM
|
||||||
|
Valve IJ has flow rate=24; tunnels lead to valves XN, WE
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves LK, AP, IZ, PC, QD
|
||||||
|
Valve KG has flow rate=0; tunnels lead to valves KD, CS
|
||||||
|
Valve QV has flow rate=0; tunnels lead to valves XM, II
|
||||||
|
Valve PC has flow rate=0; tunnels lead to valves AA, YF
|
||||||
|
Valve GJ has flow rate=20; tunnel leads to valve RI
|
||||||
|
Valve UV has flow rate=0; tunnels lead to valves UK, AE
|
||||||
|
Valve IR has flow rate=0; tunnels lead to valves EU, AE
|
||||||
|
Valve EU has flow rate=13; tunnels lead to valves IR, DT, XA, ON
|
||||||
|
Valve ED has flow rate=0; tunnels lead to valves XN, CO
|
||||||
|
Valve DT has flow rate=0; tunnels lead to valves EU, UK
|
||||||
|
Valve YE has flow rate=0; tunnels lead to valves XM, WS
|
||||||
|
Valve AD has flow rate=0; tunnels lead to valves JW, SE
|
||||||
|
Valve WE has flow rate=0; tunnels lead to valves IJ, NA
|
||||||
|
Valve UK has flow rate=5; tunnels lead to valves UV, DT, QD, HU
|
||||||
|
Valve YR has flow rate=0; tunnels lead to valves OS, SE
|
||||||
|
Valve II has flow rate=0; tunnels lead to valves QV, DS
|
||||||
|
Valve GT has flow rate=0; tunnels lead to valves CS, MN
|
||||||
|
Valve YH has flow rate=0; tunnels lead to valves BS, QB
|
||||||
|
Valve BQ has flow rate=0; tunnels lead to valves XM, KF
|
||||||
|
Valve OS has flow rate=0; tunnels lead to valves YR, NA
|
||||||
|
Valve WH has flow rate=0; tunnels lead to valves QB, HA
|
||||||
|
Valve QB has flow rate=4; tunnels lead to valves WH, KD, YH, IZ
|
||||||
|
Valve ON has flow rate=0; tunnels lead to valves AP, EU
|
||||||
|
Valve IZ has flow rate=0; tunnels lead to valves AA, QB
|
||||||
|
Valve MN has flow rate=25; tunnel leads to valve GT
|
||||||
|
Valve CG has flow rate=0; tunnels lead to valves XA, QN
|
||||||
|
Valve QD has flow rate=0; tunnels lead to valves UK, AA
|
||||||
|
Valve AL has flow rate=0; tunnels lead to valves KF, TR
|
||||||
|
Valve XN has flow rate=0; tunnels lead to valves ED, IJ
|
||||||
|
Valve WS has flow rate=0; tunnels lead to valves YE, CS
|
||||||
|
Valve CO has flow rate=18; tunnels lead to valves ED, PT, HU
|
||||||
|
Valve PT has flow rate=0; tunnels lead to valves CO, AE
|
||||||
|
Valve RI has flow rate=0; tunnels lead to valves QN, GJ
|
||||||
|
Valve CS has flow rate=9; tunnels lead to valves YF, GT, WS, TR, KG
|
||||||
|
Valve YF has flow rate=0; tunnels lead to valves PC, CS
|
||||||
|
Valve NA has flow rate=23; tunnels lead to valves OS, WE
|
||||||
|
Valve KF has flow rate=12; tunnels lead to valves HA, AL, JW, BQ
|
||||||
|
Valve XM has flow rate=3; tunnels lead to valves LK, QV, YE, BS, BQ
|
152
16/solution.mjs
Normal file
152
16/solution.mjs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
|
const input = readFileSync('input', 'utf-8');
|
||||||
|
|
||||||
|
|
||||||
|
const valves = new Map(input
|
||||||
|
.split('\n')
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(line => {
|
||||||
|
const valve = line.match(/Valve (\w+)/)[1];
|
||||||
|
const rate = parseInt(line.match(/rate=(\d+)/)[1]);
|
||||||
|
const to = line.match(/valves? (.*)/)[1].split(', ');
|
||||||
|
return [valve, {valve, rate, to}];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
function shortestPath(v, vDest, path=[]) {
|
||||||
|
const valve = valves.get(v);
|
||||||
|
|
||||||
|
if (valve.to.includes(vDest)) {
|
||||||
|
return [...path, v, vDest];
|
||||||
|
}
|
||||||
|
return valve.to
|
||||||
|
.filter(to => !path.includes(to))
|
||||||
|
.map(to => shortestPath(to, vDest, [...path, v]))
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort((p1, p2) => p1.length - p2.length)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a property to all valves containing links to all other valves with a
|
||||||
|
// flow rate greater than 0 and the time it will take to reach them
|
||||||
|
const valvesWithFlow = [...valves.values()]
|
||||||
|
.filter(valve => valve.rate > 0);
|
||||||
|
for (const valve of valves.values()) {
|
||||||
|
valve.usefulTo = valvesWithFlow
|
||||||
|
.filter(vDest => vDest.valve !== valve.valve)
|
||||||
|
.map(vDest => ({
|
||||||
|
valve: vDest.valve,
|
||||||
|
time: shortestPath(valve.valve, vDest.valve).length - 1,
|
||||||
|
rate: vDest.rate
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function product(...arrs) {
|
||||||
|
if (!arrs.length) return [];
|
||||||
|
return arrs.reduce((result, arr) =>
|
||||||
|
result.flatMap(r =>
|
||||||
|
arr.map(a => [...r, a])
|
||||||
|
),
|
||||||
|
[[]]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// General solution for n players
|
||||||
|
function solve(players, rate=0) {
|
||||||
|
for (const player of players) {
|
||||||
|
const valve = valves.get(player.path[player.path.length - 1]);
|
||||||
|
|
||||||
|
if (valve.rate > 0 && !player.opened) {
|
||||||
|
player.opened = true;
|
||||||
|
player.timeRemaining -= 1;
|
||||||
|
rate += valve.rate * Math.max(0, player.timeRemaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of valve names which haven't been visited
|
||||||
|
const unvisitedValves = valvesWithFlow
|
||||||
|
.map(v => v.valve)
|
||||||
|
.filter(valve => !players.find(p => p.path.includes(valve)));
|
||||||
|
|
||||||
|
// Exit conditions
|
||||||
|
if (
|
||||||
|
unvisitedValves.length === 0 ||
|
||||||
|
players.every(player => player.timeRemaining <= 0)
|
||||||
|
) {
|
||||||
|
return [rate, players];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide who is moving
|
||||||
|
const maxTimeRemaining = players.reduce(
|
||||||
|
(max, player) => Math.max(max, player.timeRemaining),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const movingPlayers = players.filter(
|
||||||
|
player => player.timeRemaining === maxTimeRemaining
|
||||||
|
);
|
||||||
|
const nonMovingPlayers = players.filter(
|
||||||
|
player => !movingPlayers.includes(player)
|
||||||
|
);
|
||||||
|
|
||||||
|
const playerMoves = product(...movingPlayers
|
||||||
|
.map(player => {
|
||||||
|
const valve = valves.get(player.path[player.path.length - 1]);
|
||||||
|
const destinations = valve.usefulTo
|
||||||
|
.filter(to => unvisitedValves.includes(to.valve))
|
||||||
|
.filter((to, _, tos) => !tos.find((otherTo) =>
|
||||||
|
otherTo.rate > to.rate &&
|
||||||
|
otherTo.time <= to.time
|
||||||
|
));
|
||||||
|
if (destinations.length < movingPlayers.length) {
|
||||||
|
destinations.push(undefined);
|
||||||
|
}
|
||||||
|
return destinations;
|
||||||
|
})
|
||||||
|
).filter(moves => {
|
||||||
|
const valves = moves.filter(Boolean).map(to => to.valve);
|
||||||
|
return (
|
||||||
|
valves.length !== 0 &&
|
||||||
|
new Set(valves).size === valves.length
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return playerMoves
|
||||||
|
.map(moves => {
|
||||||
|
const movedPlayers = moves.map((to, i) => {
|
||||||
|
const player = movingPlayers[i];
|
||||||
|
if (to === undefined) {
|
||||||
|
// Not moving
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
timeRemaining: player.timeRemaining - to.time,
|
||||||
|
opened: false,
|
||||||
|
path: [...player.path, to.valve]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return solve([...nonMovingPlayers, ...movedPlayers], rate);
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort(([rate1], [rate2]) => rate2 - rate1)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const solution1 = solve([{
|
||||||
|
timeRemaining: 30,
|
||||||
|
opened: false,
|
||||||
|
path: ['AA']
|
||||||
|
}]);
|
||||||
|
console.log(`Max pressure released in 30 minutes: ${solution1[0]}`);
|
||||||
|
|
||||||
|
const solution2 = solve([{
|
||||||
|
timeRemaining: 26,
|
||||||
|
opened: false,
|
||||||
|
path: ['AA']
|
||||||
|
}, {
|
||||||
|
timeRemaining: 26,
|
||||||
|
opened: false,
|
||||||
|
path: ['AA']
|
||||||
|
}]);
|
||||||
|
console.log(`Max pressure released with elephant: ${solution2[0]}`);
|
Loading…
Reference in New Issue
Block a user