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 (6301B)


      1 const fs = require('fs');
      2 
      3 function drawMap(map) {
      4   for(const row of map) {
      5     for(let i=0; i<row.length; i++) {
      6       process.stdout.write(directionChars[row[i]] || ' ');
      7     }
      8     process.stdout.write('\n');
      9   }
     10 }
     11 
     12 function mod(n, m) {
     13   return ((n%m)+m)%m;
     14 }
     15 
     16 function move(position, movement) {
     17   return [
     18     position[0] + movement[0],
     19     position[1] + movement[1],
     20   ];
     21 }
     22 
     23 // Fetch map
     24 const lines = fs.readFileSync('input', 'utf-8')
     25 // const lines = fs.readFileSync('sample', 'utf-8')
     26   .trimEnd()
     27   .split('\n');
     28 
     29 // Fetch directions
     30 const path  = lines.pop()
     31   .match(/(\d+|L|R)/g)
     32   .map(stmt => isNaN(stmt) ? stmt : parseInt(stmt))
     33 lines.pop();
     34 
     35 let mapwidth = lines
     36   .map(line => line.length)
     37   .reduce((r,a) => Math.max(r,a), 0)
     38 
     39 // Map map into something usable
     40 for(let i=0; i<lines.length; i++) {
     41   lines[i] = lines[i]
     42     .split('')
     43     .map(c => ({'.':4,'#':5}[c]));
     44 }
     45 
     46 // Define movements of directions
     47 const directions = [
     48   [  1,  0 ], // right
     49   [  0,  1 ], // down
     50   [ -1,  0 ], // left
     51   [  0, -1 ], // up
     52 ];
     53 const directionChars = ['>','v','<','^','.','#'];
     54 
     55 // How to wrap for step 1
     56 function positionStep1(map, position, movement, fallback) {
     57   fallback = fallback || position;
     58   let newpos = [...position];
     59   let stat   = lines[newpos[1]][newpos[0]];
     60 
     61   // Move until non-undefined
     62   do {
     63     newpos    = move(newpos, movement);
     64     newpos[1] = mod(newpos[1], lines.length);
     65     newpos[0] = mod(newpos[0], mapwidth);
     66     stat      = lines[newpos[1]][newpos[0]];
     67   } while('undefined' === typeof stat);
     68 
     69   // Return fallback if blocked
     70   if (stat == 5) return [...fallback];
     71   // Return new position, as it's available
     72   return newpos;
     73 }
     74 
     75 const Dir = {
     76   left: '-10',
     77   right: '10',
     78   up: '0-1',
     79   down: '01',
     80 };
     81 
     82 // Cube shape
     83 //       A-----B-----C
     84 //       |     |     |
     85 //       |  a  |  b  |
     86 //       |     |     |
     87 //       D-----E-----F
     88 //       |     |
     89 //       |  c  |
     90 //       |     |
     91 // D-----G-----F
     92 // |     |     |
     93 // |  d  |  e  |
     94 // |     |     |
     95 // A-----H-----C
     96 // |     |
     97 // |  f  |
     98 // |     |
     99 // B-----C
    100 
    101 // Calculate wrapping method for step 2
    102 // Splits into 9 surfaces (manual edge wrapping)
    103 const surfaceSize = lines[0].length / 3;
    104 const x=0, y=1;
    105 function positionStep2(map, position, movement) {
    106   let newpos = move(position, movement);
    107   let aDir   = movement.join('');
    108   let newdir = directions.indexOf(movement);
    109 
    110   // AB, a > f
    111   if (position[x] >= 50 && position[x] < 100 && position[y] == 0 && aDir == Dir.up) {
    112     newpos = [0, position[x] - 50 + 150];
    113     newdir = 0; // right
    114   }
    115   // BC, b > f
    116   if (position[x] >= 100 && position[x] < 150 && position[y] == 0 && aDir == Dir.up) {
    117     newpos = [ position[x] - 100, 199 ];
    118     newdir = 3; // up
    119   }
    120   // AD, a > d
    121   if (position[x] == 50 && position[y] < 50 && aDir == Dir.left) {
    122     newpos = [ 0, 149 - position[y] ];
    123     newdir = 0; // right
    124   }
    125   // CF, b > e
    126   if (position[x] == 149 && position[y] < 50 && aDir == Dir.right) {
    127     newpos = [position[x] - 50, 149 - position[y]];
    128     newdir = 2; // left
    129   }
    130   // EF, b > c
    131   if (position[x] >= 100 && position[y] == 49 && aDir == Dir.down) {
    132     newpos = [99, position[x] - 50];
    133     newdir = 2; // left
    134   }
    135   // DG, c > d
    136   if (position[x] == 50 && position[y] >= 50 && position[y] < 100 && aDir == Dir.left) {
    137     newpos = [position[y] - 50, 100];
    138     newdir = 1; // down
    139   }
    140   // EF, c > b
    141   if (position[x] == 99 && position[y] >= 50 && position[y] < 100 && aDir == Dir.right) {
    142     newpos = [position[y] + 50, 49];
    143     newdir = 3; // up
    144   }
    145   // DG, d > c
    146   if (position[x] < 50 && position[y] == 100 && aDir == Dir.up) {
    147     newpos = [50, position[x] + 50];
    148     newdir = 0; // right
    149   }
    150   // AD, d > a
    151   if (position[x] == 0 && position[y] >= 100 && position[y] < 150 && aDir == Dir.left) {
    152     newpos = [50, 149 - position[y]];
    153     newdir = 0; // right
    154   }
    155   // CF, e > b
    156   if (position[x] == 99 && position[y] >= 100 && position[y] < 150 && aDir == Dir.right) {
    157     newpos = [149, 149 - position[y]];
    158     newdir = 2; // left
    159   }
    160   // CH, e > f
    161   if (position[x] >= 50 && position[x] < 100 && position[y] == 149 && aDir == Dir.down) {
    162     newpos = [49, position[x] + 100];
    163     newdir = 2; // left
    164   }
    165   // AB, f > a
    166   if (position[x] == 0 && position[y] >= 150 && aDir == Dir.left) {
    167     newpos = [position[y] - 100, 0];
    168     newdir = 1; // down
    169   }
    170   // CH, f > e
    171   if (position[x] == 49 && position[y] >= 150 && aDir == Dir.right) {
    172     newpos = [position[y] - 100, 149];
    173     newdir = 3; // up
    174   }
    175   // BC, f > b
    176   if (position[x] < 50 && position[y] == 199 && aDir == Dir.down) {
    177     newpos = [position[x] + 100, 0];
    178     newdir = 1; // down
    179   }
    180 
    181   // Revert if we ran into a wall
    182   const stat = lines[newpos[y]][newpos[x]];
    183   if (stat == 5) {
    184     newpos = [...position];
    185     newdir = directions.indexOf(movement);
    186   }
    187 
    188   return [newpos, newdir];
    189 }
    190 
    191 
    192 
    193 // Define our character's position
    194 const characters = [
    195   // {
    196   //   pos: [
    197   //     Math.min(
    198   //       lines[0].indexOf(4),
    199   //       lines[0].indexOf(5),
    200   //     ),
    201   //     0,
    202   //   ],
    203   //   dir: 0,
    204   //   mv() {
    205   //     this.pos = positionStep1(lines, this.pos, directions[this.dir]);
    206   //   }
    207   // },
    208   {
    209     pos: [
    210       Math.min(
    211         lines[0].indexOf(4),
    212         lines[0].indexOf(5),
    213       ),
    214       0,
    215     ],
    216     surface: surfaceSize == 12 ?
    217       [ 2, 0 ] :
    218       [ 1, 0 ],
    219     dir: 0,
    220     mv() {
    221       let [pos,dir] = positionStep2(lines, this.pos, directions[this.dir]);
    222       this.pos = pos;
    223       this.dir = dir;
    224     }
    225   },
    226 ];
    227 
    228 // Go over the instructions
    229 for(let stmt of path) {
    230   for(const character of characters) {
    231     lines[character.pos[1]][character.pos[0]] = character.dir;
    232     if(isNaN(stmt)) {
    233       const c = stmt == 'R' ? 1 : -1;
    234       character.dir = mod(character.dir + c, directions.length);
    235       lines[character.pos[1]][character.pos[0]] = character.dir;
    236     } else {
    237       // Move along
    238       for(let i=0; i<stmt; i++) {
    239         character.mv();
    240         lines[character.pos[1]][character.pos[0]] = character.dir;
    241       }
    242     }
    243   }
    244 }
    245 
    246 drawMap(lines);
    247 
    248 // Output characters and their password
    249 for(let character of characters) {
    250   console.log({ character, password: ((character.pos[1]+1)*1000) + ((character.pos[0]+1)*4) + character.dir });
    251 }
    252 
    253 // let position = [
    254 //   0
    255 // ];
    256 // let direction = 0;
    257 
    258 
    259 
    260 
    261 
    262 // process.stdout.write(input);