index.js (3708B)
1 const fs = require('fs'); 2 const through = require('through2'); 3 const line_by_line = require('../common/line-for-line'); 4 5 String.prototype.startsWith = function(subject) { 6 return this.substr(0, subject.length) === subject; 7 }; 8 9 const area = []; 10 let sides = 0; 11 12 let minx = Infinity; 13 let miny = Infinity; 14 let minz = Infinity; 15 let maxx = -Infinity; 16 let maxy = -Infinity; 17 let maxz = -Infinity; 18 19 20 function instantiate(area, x, y, z) { 21 if (!area[x-1]) area[x-1] = []; 22 if (!area[x-1][y-1]) area[x-1][y-1] = []; 23 if (!area[x-1][y ]) area[x-1][y ] = []; 24 if (!area[x-1][y+1]) area[x-1][y+1] = []; 25 if (!area[x ]) area[x ] = []; 26 if (!area[x ][y-1]) area[x ][y-1] = []; 27 if (!area[x ][y ]) area[x ][y ] = []; 28 if (!area[x ][y+1]) area[x ][y+1] = []; 29 if (!area[x+1]) area[x+1] = []; 30 if (!area[x+1][y-1]) area[x+1][y-1] = []; 31 if (!area[x+1][y ]) area[x+1][y ] = []; 32 if (!area[x+1][y+1]) area[x+1][y+1] = []; 33 } 34 35 // fs.createReadStream('sample') 36 fs.createReadStream('input') 37 .pipe(line_by_line()) 38 39 // Minor parsing 40 .pipe(through.obj(function(line, enc, cb) { 41 line = line.toString(); 42 const [x,y,z] = line.split(',').map(n => parseInt(n)); 43 44 // Ensure the location exists 45 instantiate(area, x, y, z); 46 47 // Check all sides if covered 48 // +1 or -1, as either showing a new side or hiding another's 49 if (area[x-1][y ][z ]) { sides--; } else { sides++ }; 50 if (area[x+1][y ][z ]) { sides--; } else { sides++ }; 51 if (area[x ][y-1][z ]) { sides--; } else { sides++ }; 52 if (area[x ][y+1][z ]) { sides--; } else { sides++ }; 53 if (area[x ][y ][z-1]) { sides--; } else { sides++ }; 54 if (area[x ][y ][z+1]) { sides--; } else { sides++ }; 55 56 // Track area size 57 if (x < minx) minx = x; 58 if (y < miny) miny = y; 59 if (z < minz) minz = z; 60 if (x > maxx) maxx = x; 61 if (y > maxy) maxy = y; 62 if (z > maxz) maxz = z; 63 64 // Mark our spot as taken by rock 65 area[x][y][z] = 1; 66 67 console.log({ line, x, y, z, sides }); 68 cb(); 69 })) 70 71 .on('finish', () => { 72 console.log('loaded'); 73 74 // Expand area by 1 in all directions, so we steam can travel to all edges 75 minx -= 1; 76 miny -= 1; 77 minz -= 1; 78 maxx += 1; 79 maxy += 1; 80 maxz += 1; 81 82 // Mark our starting position as steam-filled 83 instantiate(area, minx, miny, minz); 84 area[minx][miny][minz] = 2; 85 86 let edges = 0; 87 let checked = 0; 88 89 // Fill the area with steam 90 let openset = [[minx,miny,minz]]; 91 while(openset.length) { 92 console.log(openset.length); 93 const test = openset.pop(); 94 95 // Directions for testing 96 // No diagonals 97 const [x,y,z] = test; 98 let directions = [ 99 [x-1,y ,z ], 100 [x+1,y ,z ], 101 [x ,y-1,z ], 102 [x ,y+1,z ], 103 [x ,y ,z-1], 104 [x ,y ,z+1], 105 ]; 106 107 for(const direction of directions) { 108 const [x,y,z] = direction; 109 110 // out-of-bounds = skip 111 if (x<minx) continue; 112 if (y<miny) continue; 113 if (z<minz) continue; 114 if (x>maxx) continue; 115 if (y>maxy) continue; 116 if (z>maxz) continue; 117 118 // Ensure our test location and surroundings exist 119 instantiate(area, x, y, z); 120 121 // If filled by steam already, skip test location 122 if (area[x][y][z] == 2) continue; 123 124 // If filled by rock, mark the direction as an edge & don't expand there 125 if (area[x][y][z] == 1) { 126 edges++; 127 continue; 128 } 129 130 // Here = space is open 131 // Mark as steam and add to testing locations 132 area[x][y][z] = 2; 133 openset.push([x,y,z]); 134 } 135 } 136 137 console.log({ sides, edges }); 138 });