// Comnbining all ranges (min to max) from each beacon at each level of Y may be fast enough const fs = require('fs/promises'); const sum = (arr) => arr.reduce((total, num) => total+num, 0); const arrayOfLength = n => Array.from(Array(n).keys()).map(() => {}); const parseXY = str => str.match(/x=(.*), y=(.*)$/).slice(1).map(x => parseInt(x)); const HEIGHT = 4000000; const doTouch = (a, b, a2, b2) => { const a1 = a - 1; const b1 = b + 1; if(b1 >= a2 && a1 <= b2) { return true; } return false; } const getStartEnd = (x, rad) => [x-rad, x+rad]; const getDistance = (x1, y1, x2, y2) => abs(x1 - x2) + abs(y1 - y2); const combineTouching = (a,b,c,d) => { return [Math.min(a,c), Math.max(b,d)]; } const abs = x => x < 0 ? x * -1 : x; const main = async () => { const input = (await fs.readFile("./input.txt", 'utf8')).split("\n").slice(0, -1); const sets = input.map(row => row.split(": ").map(parseXY)); const sensors = sets.map(([[sX, sY], [bX, bY]]) => { return [sX, sY, getDistance(sX, sY, bX, bY)]; }); for(let row = 0; row <= HEIGHT; row++) { const coveredArea = sensors.filter( ([_, y, rad]) => Math.abs(row-y) <= rad ).map( ([x, y, rad]) => getStartEnd(x, rad - Math.abs(row - y)) ).sort( (a, b) => a[0] - b[0] ).reduce((ranges, [a1, b1]) => { if(!ranges) { return [[a1, b1]]; } const [a, b] = ranges[ranges.length - 1]; if(doTouch(a, b, a1, b1)){ ranges[ranges.length - 1] = combineTouching(a, b, a1, b1); } else { ranges.push([a1, b1]); } return ranges; }, false); if(coveredArea.length > 1) { console.log("FOUND IT! Answer: ", (coveredArea[0][1] + 1) * 4000000 + row); process.exit(); } if(row % 100000 === 0) { console.log("DONE: ", row); } } } main();