main.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. const fs = require('fs');
  2. const readline = require('readline');
  3. const MAP_WIDTH = 7;
  4. const RESET_COLOR = '\x1B[39m';
  5. const EMPTY_CHAR = ' ';//'\x1B[39m.';
  6. function CircularBuffer(dataArr) {
  7. this.data = dataArr;
  8. this.pos = 0;
  9. }
  10. CircularBuffer.prototype.pop = function() {
  11. let data = this.data[this.pos++];
  12. while (this.pos >= this.data.length)
  13. this.pos -= this.data.length;
  14. return data;
  15. }
  16. function Arena() {
  17. this.current = null;
  18. this.data = [[]];
  19. this.dataBit = [ 0xFF ];
  20. this.dejavu = [];
  21. this.heightRemoved = 0;
  22. for (let i =0; i < MAP_WIDTH; ++i) this.data[0].push('-');
  23. }
  24. Arena.prototype.currentCover = function(px, py) {
  25. if (!this.current || this.current.x + this.current.width <= px || this.current.x > px ||
  26. this.current.y >= py || this.current.y + this.current.data.length < py)
  27. return false;
  28. return this.current.data[py - this.current.y -1][px-this.current.x];
  29. }
  30. Arena.prototype.display = function(size) {
  31. if (!size) return Promise.resolve();
  32. console.log('\033[2J');
  33. for (let i =50; i >= 0; --i) {
  34. let border = i === 0 ? '+' : '|';
  35. let line = "";
  36. for (let j =0; j < MAP_WIDTH; ++j) {
  37. if (this.currentCover(j, i))
  38. line += this.current.color + this.current.c;
  39. else if (this.data[i] && this.data[i][j])
  40. line += (typeof this.data[i][j] === 'string' ? this.data[i][j] : (this.data[i][j].color + this.data[i][j].c));
  41. else
  42. line += EMPTY_CHAR;
  43. }
  44. console.log(border+line+RESET_COLOR+border);
  45. }
  46. return new Promise((ok, ko) => setTimeout(ok, 75));
  47. }
  48. Arena.prototype.canMove = function(dx, dy) {
  49. if (this.current.x + dx < 0 || this.current.x + dx >= MAP_WIDTH || this.current.y + dy < 0) return false;
  50. return this.current.data
  51. .every((bitSet, index) => {
  52. if (dx === -1) bitSet <<= 1;
  53. else if (dx === 1) bitSet >>= 1;
  54. console.log("can move ? ", this.current.height-index+dy+this.current.y, this.dataBit[this.current.height-index+dy+this.current.y], bitSet);
  55. return (this.dataBit[this.current.height-index+dy+this.current.y] || 0x00) & bitSet != 0;
  56. });
  57. }
  58. Arena.prototype.move = async function(dx, dy, displaySize) {
  59. await this.display(displaySize);
  60. if (!this.canMove(dx, dy))
  61. return false;
  62. this.current.x += dx;
  63. this.current.y += dy;
  64. return true;
  65. }
  66. Arena.prototype.stackSize = function(pos) {
  67. for (let i = this.dataBit.length-1; i > 0; --i) {
  68. if (this.dataBit[i][1 << pos])
  69. return i <= 0 ? Infinity : i;
  70. }
  71. return Infinity;
  72. }
  73. Arena.prototype.optimHeight = function() {
  74. let max = Infinity;
  75. for (let i =0; i < MAP_WIDTH; ++i)
  76. max = Math.min(max, this.stackSize(i));
  77. if (max !== Infinity) {
  78. this.heightRemoved += max;
  79. while (max-- > 0) {
  80. this.data.shift();
  81. this.dataBit.shift();
  82. }
  83. }
  84. }
  85. Arena.prototype.nextRock = async function(pieces, jetStream, displaySize, round) {
  86. const colors = [ '\033[31m', '\033[32m', '\033[33m', '\033[35m', '\033[36m' ];
  87. const chars = ['@', '!', '$', '%', '+', '=', '?', '#'];
  88. let piece = pieces.pop();
  89. let currentData = piece.map(i => i.split('').map(i => i === '#'));
  90. this.current = {
  91. data: piece.map(i => i.split('').map(i => i === '#')),
  92. color: colors[Math.floor(Math.random() * colors.length)],
  93. x: 2,
  94. y: this.data.length +2,
  95. c: chars[Math.floor(Math.random() * chars.length)],
  96. height: 0,
  97. width: 0
  98. };
  99. let currentBits = [];
  100. for (let i of this.current.data) {
  101. let b = 0x00;
  102. for (let j =0; j < i.length; ++j)
  103. b |= i[j]<<j;
  104. currentBits.push(b);
  105. }
  106. this.current.data = currentBits;
  107. this.current.height = this.current.data.length;
  108. this.current.width = currentData[0].length;
  109. do {
  110. await this.move(jetStream.pop(), 0, displaySize);
  111. } while (await this.move(0, -1, displaySize));
  112. currentData
  113. .map((line, y) =>
  114. line.map((data, x) => data ? [x+this.current.x, this.current.height-y+this.current.y] : undefined))
  115. .reduce((acc, i) => (acc || []).concat(i))
  116. .filter(i => !!i)
  117. .forEach(i => {
  118. while (this.data.length <= i[1]) {
  119. this.data.push([]);
  120. this.dataBit.push(0x00);
  121. }
  122. this.data[i[1]][i[0]] = {
  123. color: this.current.color,
  124. c: this.current.c
  125. };
  126. this.dataBit[i[1]] |= (1 << i[0]);
  127. });
  128. this.current = null;
  129. this.dejavu[pieces.pos+'x'+jetStream.pos] = { piece: pieces.pos, jetStream: jetStream.pos, index: round };
  130. (round %500 === 0) && this.optimHeight();
  131. await this.display(displaySize);
  132. }
  133. const SCREEN_SIZE = 60;
  134. //const ProgressBar = require('progress');
  135. async function main() {
  136. let arena = new Arena();
  137. let jetStream = null;
  138. let pieces = new CircularBuffer([
  139. ["####"],
  140. [" # ", "###", " # "],
  141. [" #", " #", "###"],
  142. ["#", "#", "#", "#"],
  143. ["##", "##"]
  144. ]);
  145. for await (let line of readline.createInterface({ input: process.stdin })) {
  146. jetStream = new CircularBuffer(line.split('').map(i => i === '<' ? -1 : +1));
  147. break;
  148. }
  149. let i =0;
  150. for (; i < 2022; ++i)
  151. await arena.nextRock(pieces, jetStream, 0, i);
  152. console.log("Part 1", arena.heightRemoved + arena.data.length -1);
  153. return;
  154. //let Progress = new ProgressBar(':bar', { total: 1000000000000 });
  155. for (; i < 1000000000000; ++i) {
  156. arena.nextRock(pieces, jetStream, 0, i);
  157. //Progress.tick();
  158. }
  159. console.log("\n\nPart 2", arena.heightRemoved + arena.data.length -1);
  160. };
  161. (main());