From 562e2f4737ba0c5cd9eb5f21416a40bab0326adf Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Thu, 15 Dec 2022 14:35:55 -0500 Subject: [PATCH 01/10] part 1 --- 2022/15/part1.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2022/15/part2.js | 4 ++++ 2022/15/sample | 14 ++++++++++++++ 2022/15/test.js | 25 +++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 2022/15/part1.js create mode 100644 2022/15/part2.js create mode 100644 2022/15/sample create mode 100644 2022/15/test.js diff --git a/2022/15/part1.js b/2022/15/part1.js new file mode 100644 index 0000000..64861c7 --- /dev/null +++ b/2022/15/part1.js @@ -0,0 +1,44 @@ +import * as R from "remeda"; + +import { readFile } from "../05/part1.js"; + +import V from '@yanick/vyktor'; + +const readInput = (...args) => + R.pipe( + readFile(...args), + (lines) => lines.split("\n"), + R.compact, // remove last line + R.map(line => line.match(/x=.*?y=\d+/g).map(str => + str.match(/-?\d+/g).map(x => parseInt(x))).map( + coords => V(coords) + ) + )); + +export const puzzleInput = readInput(import.meta.url, "input"); +export const sample = readInput(import.meta.url, "sample"); + +export const unbeaconAtLine = targetLine => R.createPipe( + R.map( ([x,y]) => [ x, x.manhattanDistance(y) ] ), + R.filter( +e => ( + ( e[0].y - e[1] <= targetLine) && + ( e[0].y + e[1] >= targetLine) + ) + ), + R.map( + e => { + const l = e[1] - Math.abs(targetLine - e[0].y); + + return R.range( + e[0].x - l, + e[0].x + l, + ) } + ), + R.flatten, + R.uniq, + x => x.length + + ); + +export default unbeaconAtLine(2000000); diff --git a/2022/15/part2.js b/2022/15/part2.js new file mode 100644 index 0000000..10fc179 --- /dev/null +++ b/2022/15/part2.js @@ -0,0 +1,4 @@ +import * as R from "remeda"; + + +export default () => {}; diff --git a/2022/15/sample b/2022/15/sample new file mode 100644 index 0000000..a612424 --- /dev/null +++ b/2022/15/sample @@ -0,0 +1,14 @@ +Sensor at x=2, y=18: closest beacon is at x=-2, y=15 +Sensor at x=9, y=16: closest beacon is at x=10, y=16 +Sensor at x=13, y=2: closest beacon is at x=15, y=3 +Sensor at x=12, y=14: closest beacon is at x=10, y=16 +Sensor at x=10, y=20: closest beacon is at x=10, y=16 +Sensor at x=14, y=17: closest beacon is at x=10, y=16 +Sensor at x=8, y=7: closest beacon is at x=2, y=10 +Sensor at x=2, y=0: closest beacon is at x=2, y=10 +Sensor at x=0, y=11: closest beacon is at x=2, y=10 +Sensor at x=20, y=14: closest beacon is at x=25, y=17 +Sensor at x=17, y=20: closest beacon is at x=21, y=22 +Sensor at x=16, y=7: closest beacon is at x=15, y=3 +Sensor at x=14, y=3: closest beacon is at x=15, y=3 +Sensor at x=20, y=1: closest beacon is at x=15, y=3 diff --git a/2022/15/test.js b/2022/15/test.js new file mode 100644 index 0000000..c843547 --- /dev/null +++ b/2022/15/test.js @@ -0,0 +1,25 @@ +import { test, expect, describe } from "vitest"; + +import { expectSolution } from "../01/main.js"; +import part1, { sample, puzzleInput, unbeaconAtLine } from "./part1.js"; +import part2 from "./part2.js"; + +describe("part 1", () => { + test('readInput', () => { + expect(sample[0][0].toArray()).toEqual([2, 18]); + }); + + test('sample', () => { + expect(unbeaconAtLine(10)(sample)).toEqual(26); + }); + + test("solution", () => { + expectSolution(part1(puzzleInput)).toEqual(5525990); + }); +}); + +describe("part 2", () => { + test.todo("solution", () => { + expectSolution(part2(puzzleInput)).toEqual("TODO"); + }); +}); From 69f0bf3f1c50c10d3e57e652812dce6c66e912e5 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sun, 18 Dec 2022 11:57:22 -0500 Subject: [PATCH 02/10] faster part 1 --- 2022/15/part1.js | 55 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/2022/15/part1.js b/2022/15/part1.js index 64861c7..72190fd 100644 --- a/2022/15/part1.js +++ b/2022/15/part1.js @@ -1,8 +1,10 @@ import * as R from "remeda"; +import { passthru } from "../08/part1.js"; import { readFile } from "../05/part1.js"; import V from '@yanick/vyktor'; +import { createLogger } from "vite"; const readInput = (...args) => R.pipe( @@ -18,7 +20,38 @@ const readInput = (...args) => export const puzzleInput = readInput(import.meta.url, "input"); export const sample = readInput(import.meta.url, "sample"); -export const unbeaconAtLine = targetLine => R.createPipe( +/** @returns [number,number][] */ +const mergeRanges = ( ranges ) => + ranges.reduce( (accum,range) => { + if( accum.length === 0 ) return [ range ]; + if( R.last( accum )[1] < range[0] ) { + accum.push(range); + } + else { + R.last(accum)[1] = Math.max( + R.last(accum)[1], range[1] + ) + } + return accum; + }, [] ); + +const spy = passthru( x => console.log(x) ); + +const entriesInRange = (targetLine,entries) => { + + entries = R.uniqBy(entries.map(([_,beacon])=>beacon).filter( beacon => beacon?.y === targetLine ), (x) => x.toString()); + + console.log(entries); + + return range => { + return entries.filter( + entry => (entry.x >= range[0]) && (entry.x <= range[1]) + ).length + } +}; + +export const unbeaconAtLine = targetLine => entries => R.pipe( + entries, R.map( ([x,y]) => [ x, x.manhattanDistance(y) ] ), R.filter( e => ( @@ -30,15 +63,21 @@ e => ( e => { const l = e[1] - Math.abs(targetLine - e[0].y); - return R.range( + return [ e[0].x - l, - e[0].x + l, - ) } + e[0].x + l ] + } ), - R.flatten, - R.uniq, - x => x.length - + spy, + (ranges) => + ranges.sort( (a,b) => { + return (a[0] - b[0]) || (a[1]-b[1]); + } ) + , + spy, + mergeRanges, + spy, + R.sumBy( range => range[1] - range[0] + 1 - entriesInRange(targetLine,entries)(range) ) ); export default unbeaconAtLine(2000000); From 0a281c084ce129189932594d9644e541b90723e5 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sun, 18 Dec 2022 13:39:06 -0500 Subject: [PATCH 03/10] part 2, crummy --- 2022/15/part1.js | 2 +- 2022/15/part2.js | 22 +++++++++++++++++++++- 2022/15/test.js | 7 +++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/2022/15/part1.js b/2022/15/part1.js index 72190fd..35851b7 100644 --- a/2022/15/part1.js +++ b/2022/15/part1.js @@ -11,7 +11,7 @@ const readInput = (...args) => readFile(...args), (lines) => lines.split("\n"), R.compact, // remove last line - R.map(line => line.match(/x=.*?y=\d+/g).map(str => + R.map(line => line.match(/x=-?.*?y=-?\d+/g).map(str => str.match(/-?\d+/g).map(x => parseInt(x))).map( coords => V(coords) ) diff --git a/2022/15/part2.js b/2022/15/part2.js index 10fc179..aeb3ead 100644 --- a/2022/15/part2.js +++ b/2022/15/part2.js @@ -1,4 +1,24 @@ import * as R from "remeda"; +import V from '@yanick/vyktor'; +export const findBeacon = max => entries => { -export default () => {}; + const nonGrata = R.uniqBy(R.flatten(entries), (x) => x.toString());; + + const deadZones = R.map( entries, ([x,y]) => [ x, x.manhattanDistance(y) ] ); + + for ( let x =0; x <= max; x++ ) { + for ( let y =0; y <= max; y++ ) { + if( nonGrata.some( p => p.x===x && p.y===y ) ) continue; + + const v = V(x,y); + if( deadZones.some( + d => d[0].manhattanDistance( v ) <= d[1] + ) ) continue; + + return x * 4000000 + y; + } + } +} + +export default findBeacon(4000000); diff --git a/2022/15/test.js b/2022/15/test.js index c843547..414fea6 100644 --- a/2022/15/test.js +++ b/2022/15/test.js @@ -2,7 +2,7 @@ import { test, expect, describe } from "vitest"; import { expectSolution } from "../01/main.js"; import part1, { sample, puzzleInput, unbeaconAtLine } from "./part1.js"; -import part2 from "./part2.js"; +import part2, { findBeacon } from "./part2.js"; describe("part 1", () => { test('readInput', () => { @@ -19,7 +19,10 @@ describe("part 1", () => { }); describe("part 2", () => { - test.todo("solution", () => { + test('sample', () => { + expect(findBeacon(20)(sample)).toEqual(56000011); + }); + test.only("solution", () => { expectSolution(part2(puzzleInput)).toEqual("TODO"); }); }); From b3cacb15ded479d79e4f0c9d9ce17d53fe0c753e Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sun, 18 Dec 2022 16:06:07 -0500 Subject: [PATCH 04/10] part 2, crummy but working --- 2022/15/part1.js | 10 ++++---- 2022/15/part2.js | 65 ++++++++++++++++++++++++++++++++++++++---------- 2022/15/test.js | 5 ++-- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/2022/15/part1.js b/2022/15/part1.js index 35851b7..a196927 100644 --- a/2022/15/part1.js +++ b/2022/15/part1.js @@ -21,8 +21,9 @@ export const puzzleInput = readInput(import.meta.url, "input"); export const sample = readInput(import.meta.url, "sample"); /** @returns [number,number][] */ -const mergeRanges = ( ranges ) => - ranges.reduce( (accum,range) => { +export const mergeRanges = ( ranges ) => { + +return ranges.reduce( (accum,range) => { if( accum.length === 0 ) return [ range ]; if( R.last( accum )[1] < range[0] ) { accum.push(range); @@ -34,15 +35,14 @@ const mergeRanges = ( ranges ) => } return accum; }, [] ); +} -const spy = passthru( x => console.log(x) ); +export const spy = passthru( x => console.log(x) ); const entriesInRange = (targetLine,entries) => { entries = R.uniqBy(entries.map(([_,beacon])=>beacon).filter( beacon => beacon?.y === targetLine ), (x) => x.toString()); - console.log(entries); - return range => { return entries.filter( entry => (entry.x >= range[0]) && (entry.x <= range[1]) diff --git a/2022/15/part2.js b/2022/15/part2.js index aeb3ead..543b6bf 100644 --- a/2022/15/part2.js +++ b/2022/15/part2.js @@ -1,23 +1,62 @@ import * as R from "remeda"; import V from '@yanick/vyktor'; +import { + spy, +mergeRanges +} from './part1.js'; + +const unbeaconAtLine = (max,targetLine,already) => entries => R.pipe( + entries, + R.map( ([x,y]) => [ x, x.manhattanDistance(y) ] ), + R.filter( +e => ( + ( e[0].y - e[1] <= targetLine) && + ( e[0].y + e[1] >= targetLine) + ) + ), + R.map( + e => { + const l = e[1] - Math.abs(targetLine - e[0].y); + + return [ + e[0].x - l, + e[0].x + l ] + } + ), + //spy, + (ranges) => [ + ...ranges, ...already.filter( v => v.y === targetLine ).map( + v => [ v.x,v.x ] + ) + ], + (ranges) => + ranges.sort( (a,b) => { + return (a[0] - b[0]) || (a[1]-b[1]); + } ) + , + // spy, + R.map( + range => [ Math.max(0,range[0]), Math.min(max,range[1])] + ), + mergeRanges, + // spy, + // R.sumBy( range => range[1] - range[0] + 1 - entriesInRange(targetLine,entries)(range) ) + ); + export const findBeacon = max => entries => { - const nonGrata = R.uniqBy(R.flatten(entries), (x) => x.toString());; + const already = entries.flat() - const deadZones = R.map( entries, ([x,y]) => [ x, x.manhattanDistance(y) ] ); - - for ( let x =0; x <= max; x++ ) { - for ( let y =0; y <= max; y++ ) { - if( nonGrata.some( p => p.x===x && p.y===y ) ) continue; - - const v = V(x,y); - if( deadZones.some( - d => d[0].manhattanDistance( v ) <= d[1] - ) ) continue; - - return x * 4000000 + y; + for (let y = 0; y <= max; y++) { + const ranges = unbeaconAtLine(max,y,already)(entries) + if( ranges.length > 1 ) { + return y + 4000000 * (ranges[0][1] +1); } + +// return 'bob'; + + // return x * 4000000 + y; } } diff --git a/2022/15/test.js b/2022/15/test.js index 414fea6..e53af8b 100644 --- a/2022/15/test.js +++ b/2022/15/test.js @@ -22,7 +22,8 @@ describe("part 2", () => { test('sample', () => { expect(findBeacon(20)(sample)).toEqual(56000011); }); - test.only("solution", () => { - expectSolution(part2(puzzleInput)).toEqual("TODO"); + test("solution", () => { + // 314 seconds! + expectSolution(part2(puzzleInput)).toEqual(11756174628223); }); }); From df0d7b92a30f2c3d01539fcc540a3663ae152d69 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sun, 18 Dec 2022 17:13:07 -0500 Subject: [PATCH 05/10] wip --- 2022/16/part1.js | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 2022/16/part2.js | 4 +++ 2022/16/sample | 10 ++++++++ 2022/16/test.js | 29 +++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 2022/16/part1.js create mode 100644 2022/16/part2.js create mode 100644 2022/16/sample create mode 100644 2022/16/test.js diff --git a/2022/16/part1.js b/2022/16/part1.js new file mode 100644 index 0000000..9809253 --- /dev/null +++ b/2022/16/part1.js @@ -0,0 +1,66 @@ +import * as R from "remeda"; +import u from "updeep"; + +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: 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 bestMoveFor(tunnels,minutesLeft,opened,location='AA',totalSteam=0,activeSteam=0) { + console.log(minutesLeft, totalSteam); + + if(minutesLeft<=0) return totalSteam; + + totalSteam += activeSteam; + + const possibilities = []; + + if(!opened.includes(location)) { + possibilities.push( + bestMoveFor( + tunnels, + minutesLeft-1, + [...opened, location], + location, + totalSteam, + activeSteam + tunnels[location].flow + ) + ) + } + + for( const exit of tunnels[location].exits ) { + possibilities.push( + bestMoveFor( + tunnels, + minutesLeft-1, + opened, + exit, + totalSteam, + activeSteam, + ) + ) + } + + return Math.max( ...possibilities ); +} + + +export default (tunnels) => { + return bestMoveFor(tunnels,30,[]); +}; diff --git a/2022/16/part2.js b/2022/16/part2.js new file mode 100644 index 0000000..10fc179 --- /dev/null +++ b/2022/16/part2.js @@ -0,0 +1,4 @@ +import * as R from "remeda"; + + +export default () => {}; diff --git a/2022/16/sample b/2022/16/sample new file mode 100644 index 0000000..9f30acc --- /dev/null +++ b/2022/16/sample @@ -0,0 +1,10 @@ +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 diff --git a/2022/16/test.js b/2022/16/test.js new file mode 100644 index 0000000..8521f1c --- /dev/null +++ b/2022/16/test.js @@ -0,0 +1,29 @@ +import { test, expect, describe } from "vitest"; + +import { expectSolution } from "../01/main.js"; +import part1, { sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; + +describe("part 1", () => { + test( "input", ()=> { + expect(sample).toMatchObject({AA: { + exists: [ + 'DD', 'II', 'BB', + ], + flow: 0, + }}) + + } ) + test.only("sample", () => { + expectSolution(part1(sample)).toEqual(1651); + }); + test.todo("solution", () => { + expectSolution(part1(puzzleInput)).toEqual("TODO"); + }); +}); + +describe("part 2", () => { + test.todo("solution", () => { + expectSolution(part2(puzzleInput)).toEqual("TODO"); + }); +}); From bc6b5259c1dc89a6aca4c64671d85671fc3b8c28 Mon Sep 17 00:00:00 2001 From: Yanick Date: Sun, 18 Dec 2022 18:42:55 -0500 Subject: [PATCH 06/10] wip --- 2022/16/part1.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/2022/16/part1.js b/2022/16/part1.js index 9809253..8a06d49 100644 --- a/2022/16/part1.js +++ b/2022/16/part1.js @@ -1,6 +1,11 @@ import * as R from "remeda"; import u from "updeep"; +import Graph from 'graphology'; +import {bidirectional} from 'graphology-shortest-path'; + +import { combinations } from "combinatorial-generators"; + import { readFile } from "../05/part1.js"; const parseLine = (line) => { @@ -62,5 +67,12 @@ function bestMoveFor(tunnels,minutesLeft,opened,location='AA',totalSteam=0,activ export default (tunnels) => { - return bestMoveFor(tunnels,30,[]); + + const graph = new Graph(); + Object.entries(tunnels).forEach( ([location, { exits }]) => { + exits.forEach( exit => graph.addEdge(location, exit) ); + }); + + console.log(graph); + }; From 1a855600cf453b9d96ed249de694673e1a6986ee Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sun, 25 Dec 2022 17:09:27 -0500 Subject: [PATCH 07/10] part 2, wip --- 2022/16/part1.js | 106 +++++++++++++++++++++++++++-------------------- 2022/16/part2.js | 70 ++++++++++++++++++++++++++++++- 2022/16/test.js | 15 ++++--- 3 files changed, 139 insertions(+), 52 deletions(-) diff --git a/2022/16/part1.js b/2022/16/part1.js index 8a06d49..859c0be 100644 --- a/2022/16/part1.js +++ b/2022/16/part1.js @@ -2,77 +2,91 @@ import * as R from "remeda"; import u from "updeep"; 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"; const parseLine = (line) => { - const {groups} = line.match( /Valve (?..).*flow rate=(?\d+).*valves? (?.*)/ ); - return [ groups.valve, { - exits: groups.exits.split(',').map( x => x.trim() ), - flow: groups.flow - } ] + 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, - ); + 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 bestMoveFor(tunnels,minutesLeft,opened,location='AA',totalSteam=0,activeSteam=0) { - console.log(minutesLeft, totalSteam); +function finalSteam(tunnels, graph, minutesLeft, possibilities, location = 'AA', activeSteam = 0) { + //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)) { - possibilities.push( - bestMoveFor( - tunnels, - minutesLeft-1, - [...opened, location], - location, - totalSteam, - activeSteam + tunnels[location].flow - ) + 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 + ) ) } - 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) => { - const graph = new Graph(); - Object.entries(tunnels).forEach( ([location, { exits }]) => { - exits.forEach( exit => graph.addEdge(location, exit) ); - }); + const possibilities = + Object.keys(tunnels).filter( + k => tunnels[k].flow + ); - console.log(graph); + const graph = buildGraph(tunnels); + + return finalSteam(tunnels, graph, 30, possibilities, 'AA', 0, 0) }; diff --git a/2022/16/part2.js b/2022/16/part2.js index 10fc179..12b2097 100644 --- a/2022/16/part2.js +++ b/2022/16/part2.js @@ -1,4 +1,72 @@ +import { bidirectional } from 'graphology-shortest-path'; 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) + +}; diff --git a/2022/16/test.js b/2022/16/test.js index 8521f1c..14f8d9d 100644 --- a/2022/16/test.js +++ b/2022/16/test.js @@ -14,15 +14,20 @@ describe("part 1", () => { }}) } ) - test.only("sample", () => { - expectSolution(part1(sample)).toEqual(1651); + test("sample", () => { + expect(part1(sample)).toEqual(1651); }); - test.todo("solution", () => { - expectSolution(part1(puzzleInput)).toEqual("TODO"); + test.only("solution", () => { + 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", () => { expectSolution(part2(puzzleInput)).toEqual("TODO"); }); From 231cc7b8835514066257fb4aea56036588ed92fa Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Mon, 2 Jan 2023 10:53:14 -0500 Subject: [PATCH 08/10] wip --- 2022/16/part2.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/2022/16/part2.js b/2022/16/part2.js index 12b2097..5f70916 100644 --- a/2022/16/part2.js +++ b/2022/16/part2.js @@ -4,13 +4,12 @@ import * as R from "remeda"; import { buildGraph } from './part1.js'; 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); + const nextToGo = locations.filter(([time]) => !time); for( const l of locations) { if( l[0] === 0 ) { @@ -22,18 +21,21 @@ function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activ let scores = []; + for ( const ntg of nextToGo ) { + for ( const next of possibilities ) { - const path = bidirectional(graph, nextToGo[1], next); + const path = bidirectional(graph, ntg[1], next); //console.log(path); - const locs = locations.map( x => x === nextToGo ? [ + const locs = locations.map( x => x === ntg ? [ path.length, next, tunnels[next].flow ] : x ); let time = Math.min( ...locs.map( ([time]) => time ) ); if (time >= minutesLeft) { + //console.log(minutesLeft, activeSteam, locations, possibilities); scores.push( minutesLeft * activeSteam ); } else { @@ -44,13 +46,14 @@ function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activ ts + finalSteam( tunnels, graph, minutesLeft - time, possibilities.filter( x => x !== next ), - locs.map( ([t,dest] ) => [ t -time, dest ]), + locs.map( ([t,dest,s] ) => [ t -time, dest,s ]), activeSteam ) ) } } + } return Math.max( ...scores ); } @@ -65,8 +68,8 @@ export default (tunnels) => { const graph = buildGraph(tunnels); return finalSteam(tunnels, graph, 26, possibilities, [ - [ 0, 'AA' ], - [ 0, 'AA' ] + [ 0, 'AA',0 ], + [ 0, 'AA',0 ] ], 0, 0) }; From 9adefbc7962c0d1a863a0ce7120f4f446ea63a31 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Mon, 2 Jan 2023 11:02:06 -0500 Subject: [PATCH 09/10] wait a minute --- 2022/16/part2.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/2022/16/part2.js b/2022/16/part2.js index 5f70916..441d100 100644 --- a/2022/16/part2.js +++ b/2022/16/part2.js @@ -1,13 +1,26 @@ import { bidirectional } from 'graphology-shortest-path'; import * as R from "remeda"; +import u from 'updeep'; import { buildGraph } from './part1.js'; -function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activeSteam = 0) { - +const findMaxSteam = (tunnels,graph) => (minutesLeft, unopened, opened, activeSteam, peeps ) => { if (minutesLeft <= 0) return 0; - if (possibilities.length === 0) return minutesLeft * activeSteam; + if (unopened.length === 0) return minutesLeft * activeSteam; + + const next = R.first( R.sortBy(peeps, R.prop('eta'))); + + if( next.eta >) + + + + +} + +function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activeSteam = 0) { + + const nextToGo = locations.filter(([time]) => !time); From 850f4f963fe9a828aca818422f9227938dc0eab1 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Thu, 30 Nov 2023 10:10:58 -0500 Subject: [PATCH 10/10] wip --- 2022/16/fast.js | 4 ++ 2022/16/part2.js | 106 +++++++++++++++++++++++------------------------ 2022/16/test.js | 6 +-- package.json | 10 ++++- 4 files changed, 67 insertions(+), 59 deletions(-) create mode 100644 2022/16/fast.js diff --git a/2022/16/fast.js b/2022/16/fast.js new file mode 100644 index 0000000..5357596 --- /dev/null +++ b/2022/16/fast.js @@ -0,0 +1,4 @@ +import part1, { sample, puzzleInput } from "./part1.js"; +import part2 from "./part2.js"; + +console.log(part2(puzzleInput)); diff --git a/2022/16/part2.js b/2022/16/part2.js index 441d100..1c649cb 100644 --- a/2022/16/part2.js +++ b/2022/16/part2.js @@ -4,71 +4,69 @@ import u from 'updeep'; import { buildGraph } from './part1.js'; -const findMaxSteam = (tunnels,graph) => (minutesLeft, unopened, opened, activeSteam, peeps ) => { - if (minutesLeft <= 0) return 0; +const findMaxSteam = (tunnels,graph, minutesLeft, unopened, opened, activeSteam, peeps ) => { - if (unopened.length === 0) return minutesLeft * activeSteam; + console.log({ unopened, activeSteam, minutesLeft}); - const next = R.first( R.sortBy(peeps, R.prop('eta'))); + let next = R.sortBy(peeps, R.prop('eta')); - if( next.eta >) + if( next[0].eta > minutesLeft ) { + return minutesLeft * activeSteam; + } + + const delta = next[0].eta; + const location = next[0].destination; + + const base = delta * activeSteam; + minutesLeft -= delta; + + activeSteam += tunnels[ next[0].destination ].flow; + opened = [ ...opened, next[0].destination ]; + + next = u.updateIn( '1.eta', eta => eta - delta, next ); + + const scores = []; -} + let nothing = true; + for ( const destination of unopened ) { + const path = bidirectional(graph, location, destination ); -function finalSteam(tunnels, graph, minutesLeft, possibilities, locations, activeSteam = 0) { - - - - const nextToGo = locations.filter(([time]) => !time); - - for( const l of locations) { - if( l[0] === 0 ) { - activeSteam += l[2]; - l[2] = 0; + if( path.length > minutesLeft) { + continue; } + nothing = false; + + next = u.updateIn( '0', { + location, + eta: path.length, + destination + },next); + + scores.push( findMaxSteam(tunnels,graph,minutesLeft, + unopened.filter( x => x !== destination ), + opened, activeSteam, next + ) ); } + if( nothing ) { + next = u.updateIn( '0', { + location, + eta: 999, + destination: 'END', + },next); - let scores = []; - - for ( const ntg of nextToGo ) { - - for ( const next of possibilities ) { - const path = bidirectional(graph, ntg[1], next); - - //console.log(path); - - const locs = locations.map( x => x === ntg ? [ - path.length, next, tunnels[next].flow - ] : x ); - - let time = Math.min( ...locs.map( ([time]) => time ) ); - - if (time >= minutesLeft) { - //console.log(minutesLeft, activeSteam, locations, possibilities); - 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,s] ) => [ t -time, dest,s ]), - activeSteam - ) - ) + scores.push( findMaxSteam(tunnels,graph,minutesLeft, + unopened, + opened, activeSteam, next + ) ); } - } - } + return base + Math.max( ...scores ); + - return Math.max( ...scores ); } export default (tunnels) => { @@ -80,9 +78,9 @@ export default (tunnels) => { const graph = buildGraph(tunnels); - return finalSteam(tunnels, graph, 26, possibilities, [ - [ 0, 'AA',0 ], - [ 0, 'AA',0 ] - ], 0, 0) + return findMaxSteam(tunnels, graph, 26, possibilities,[],0, [ + { destination: 'AA', eta: 0 }, + { destination: 'AA', eta: 0 }, + ]) }; diff --git a/2022/16/test.js b/2022/16/test.js index 14f8d9d..44c122e 100644 --- a/2022/16/test.js +++ b/2022/16/test.js @@ -17,7 +17,7 @@ describe("part 1", () => { test("sample", () => { expect(part1(sample)).toEqual(1651); }); - test.only("solution", () => { + test("solution", () => { const r= part1(puzzleInput); expect(r).toBeGreaterThan(707); expectSolution(part1(puzzleInput)).toEqual(1871); @@ -25,10 +25,10 @@ describe("part 1", () => { }); describe.only("part 2", () => { - test("sample", () => { + test.skip("sample", () => { expect(part2(sample)).toEqual(1707); }); - test.todo("solution", () => { + test("solution", () => { expectSolution(part2(puzzleInput)).toEqual("TODO"); }); }); diff --git a/package.json b/package.json index 86b09f3..b49046c 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,19 @@ "license": "ISC", "dependencies": { "@a-robu/victor": "^2.2.2", + "@yanick/vyktor": "link:../vyktor", + "combinatorial-generators": "^1.1.2", "debug": "^4.3.4", "fs-extra": "^11.1.0", + "graphology": "^0.25.1", + "graphology-shortest-path": "^2.0.1", + "graphology-types": "^0.24.5", "memoizerific": "^1.11.3", "prettier": "^2.8.0", "remeda": "^1.3.0", - "vite": "^4.0.1", - "vitest": "0.25.7" + "updeep": "^1.2.1", + "vite": "4.0.3", + "vitest": "0.26.3" }, "devDependencies": { "@vitest/ui": "^0.25.8"