advent-of-code

Entries to advent of code, multiple years
git clone git://git.finwo.net/misc/advent-of-code
Log | Files | Refs

commit c0062bef3c1e6590e98178ed81b22f2853a68ef0
parent 0d285583cd7eb162ccef53ae20164af6685ac9d3
Author: finwo <finwo@pm.me>
Date:   Wed, 14 Dec 2022 10:02:10 +0100

2022/14 solution

Diffstat:
A2022/day-14/index.js | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A2022/day-14/sample | 2++
2 files changed, 204 insertions(+), 0 deletions(-)

diff --git a/2022/day-14/index.js b/2022/day-14/index.js @@ -0,0 +1,202 @@ +const fs = require('fs'); +const through = require('through2'); +const line_by_line = require('../common/line-for-line'); + +String.prototype.startsWith = function(subject) { + return this.substr(0, subject.length) === subject; +}; + +const grid = []; +const entryPoint = [500, 0]; + +function range(start, end) { + const ret = []; + const high = Math.max(start, end); + const low = Math.min(start, end); + for(let i=low; i<=high; i++) ret.push(i); + return low == start ? ret : ret.reverse(); +} + +function plot(x, y, value = 1) { + grid[y] = grid[y] || []; + grid[y][x] = value; +} + +// Pulled straight out of wikipedia +function plotLineLow(x0, y0, x1, y1) { + let dx = x1 - x0; + let dy = y1 - y0; + let yi = 1; + if (dy < 0) { + yi = -1; + dy = -dy; + } + let D = (2 * dy) - dx; + let y = y0; + for (const x of range(x0, x1)) { + plot(x, y); + if (D > 0) { + y = y + yi; + D = D + (2 * (dy - dx)); + } else { + D = D + 2*dy; + } + } +} +function plotLineHigh(x0, y0, x1, y1) { + let dx = x1 - x0; + let dy = y1 - y0; + let xi = 1; + if (dx < 0) { + xi = -1; + dx = -dx; + } + let D = (2 * dx) - dy; + let x = x0; + for (const y of range(y0, y1)) { + plot(x, y); + if (D > 0) { + x = x + xi; + D = D + (2 * (dx - dy)); + } else { + D = D + 2*dx; + } + } +} +function plotLine(x0, y0, x1, y1) { + if (Math.abs(y1 - y0) < Math.abs(x1 - x0)) { + if (x0 > x1) { + plotLineLow(x1, y1, x0, y0) + } else { + plotLineLow(x0, y0, x1, y1) + } + } else { + if (y0 > y1) { + plotLineHigh(x1, y1, x0, y0) + } else { + plotLineHigh(x0, y0, x1, y1) + } + } +} + +let minx = entryPoint[0]; +let maxx = entryPoint[0]; +let miny = entryPoint[1]; +let maxy = entryPoint[1]; + +function drawArea() { + // Draw area + for(let y=miny; y<=maxy; y++) { + for(let x=minx; x<=maxx; x++) { + if (grid[y] && grid[y][x] == 1) { + process.stdout.write('#'); + } else if (grid[y] && grid[y][x] == 2) { + process.stdout.write('+'); + } else if (grid[y] && grid[y][x] == 3) { + process.stdout.write('o'); + } else { + process.stdout.write('.'); + } + } + process.stdout.write('\n'); + } +} + + + +let units = 0; + +fs.createReadStream('input') + .pipe(line_by_line()) + + // Minor parsing + .pipe(through(function(line, enc, cb) { + line = line.toString(); + + // Turn into line point coordinates + const points = line + .split(' -> ') + .map(point => point.split(',').map(a => parseInt(a))); + + // Track range to visualize later + points.forEach(point => { + minx = Math.min(minx, point[0]); + miny = Math.min(miny, point[1]); + maxx = Math.max(maxx, point[0]); + maxy = Math.max(maxy, point[1]); + }); + + // "draw" lines + let lastPoint = points.shift(); + while(points.length) { + const point = points.shift(); + plotLine( + lastPoint[0], lastPoint[1], + point[0], point[1], + ); + lastPoint = point; + } + + cb(); + })) + + .on('finish', () => { + + // Mark entrypoint + plot(entryPoint[0], entryPoint[1], 2); + + // Mark floor + maxy+=2; + plotLine( + minx-10000, maxy, + maxx+10000, maxy, + ); + minx -= 10; + maxx += 10; + + // Let sand fall in + while(true) { + + let unit = [...entryPoint]; + + while(true) { + if (unit[1] > maxy) { + break; + } + if (!(grid[unit[1]+1])) { + unit[1]++; + } else if (!(grid[unit[1]+1][unit[0]])) { + unit[1]++; + } else if (!(grid[unit[1]+1][unit[0]-1])) { + unit[0]--; + unit[1]++; + } else if (!(grid[unit[1]+1][unit[0]+1])) { + unit[0]++; + unit[1]++; + } else { + // rest + break; + } + } + + plot(unit[0], unit[1], 3); + units++; + + if (units%100 == 0) { + drawArea(); + process.stdout.write('\n'.repeat(3)); + } + + if ( + (unit[1] > maxy) || + (unit[0] == entryPoint[0] && unit[1] == entryPoint[1]) + ) { + break; + } + } + + + drawArea(); + console.log({ units }); + console.log('finish'); + }); diff --git a/2022/day-14/sample b/2022/day-14/sample @@ -0,0 +1,2 @@ +498,4 -> 498,6 -> 496,6 +503,4 -> 502,4 -> 502,9 -> 494,9