advent-of-code

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

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   });