|
|
@@ -0,0 +1,177 @@
|
|
|
+
|
|
|
+const fs = require('fs');
|
|
|
+const readline = require('readline');
|
|
|
+
|
|
|
+const MAP_WIDTH = 7;
|
|
|
+const RESET_COLOR = '\x1B[39m';
|
|
|
+const EMPTY_CHAR = ' ';//'\x1B[39m.';
|
|
|
+
|
|
|
+function CircularBuffer(dataArr) {
|
|
|
+ this.data = dataArr;
|
|
|
+ this.pos = 0;
|
|
|
+}
|
|
|
+
|
|
|
+CircularBuffer.prototype.pop = function() {
|
|
|
+ let data = this.data[this.pos++];
|
|
|
+ while (this.pos >= this.data.length)
|
|
|
+ this.pos -= this.data.length;
|
|
|
+ return data;
|
|
|
+}
|
|
|
+
|
|
|
+function Arena() {
|
|
|
+ this.current = null;
|
|
|
+ this.data = [[]];
|
|
|
+ this.dataBit = [ 0xFF ];
|
|
|
+ this.dejavu = [];
|
|
|
+ this.heightRemoved = 0;
|
|
|
+ for (let i =0; i < MAP_WIDTH; ++i) this.data[0].push('-');
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.currentCover = function(px, py) {
|
|
|
+ if (!this.current || this.current.x + this.current.width <= px || this.current.x > px ||
|
|
|
+ this.current.y >= py || this.current.y + this.current.data.length < py)
|
|
|
+ return false;
|
|
|
+ return this.current.data[py - this.current.y -1][px-this.current.x];
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.display = function(size) {
|
|
|
+ if (!size) return Promise.resolve();
|
|
|
+ console.log('\033[2J');
|
|
|
+ for (let i =50; i >= 0; --i) {
|
|
|
+ let border = i === 0 ? '+' : '|';
|
|
|
+ let line = "";
|
|
|
+ for (let j =0; j < MAP_WIDTH; ++j) {
|
|
|
+ if (this.currentCover(j, i))
|
|
|
+ line += this.current.color + this.current.c;
|
|
|
+ else if (this.data[i] && this.data[i][j])
|
|
|
+ line += (typeof this.data[i][j] === 'string' ? this.data[i][j] : (this.data[i][j].color + this.data[i][j].c));
|
|
|
+ else
|
|
|
+ line += EMPTY_CHAR;
|
|
|
+ }
|
|
|
+ console.log(border+line+RESET_COLOR+border);
|
|
|
+ }
|
|
|
+ return new Promise((ok, ko) => setTimeout(ok, 75));
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.canMove = function(dx, dy) {
|
|
|
+ if (this.current.x + dx < 0 || this.current.x + dx >= MAP_WIDTH || this.current.y + dy < 0) return false;
|
|
|
+ return this.current.data
|
|
|
+ .every((bitSet, index) => {
|
|
|
+ if (dx === -1) bitSet <<= 1;
|
|
|
+ else if (dx === 1) bitSet >>= 1;
|
|
|
+ console.log("can move ? ", this.current.height-index+dy+this.current.y, this.dataBit[this.current.height-index+dy+this.current.y], bitSet);
|
|
|
+ return (this.dataBit[this.current.height-index+dy+this.current.y] || 0x00) & bitSet != 0;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.move = async function(dx, dy, displaySize) {
|
|
|
+ await this.display(displaySize);
|
|
|
+ if (!this.canMove(dx, dy))
|
|
|
+ return false;
|
|
|
+ this.current.x += dx;
|
|
|
+ this.current.y += dy;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.stackSize = function(pos) {
|
|
|
+ for (let i = this.dataBit.length-1; i > 0; --i) {
|
|
|
+ if (this.dataBit[i][1 << pos])
|
|
|
+ return i <= 0 ? Infinity : i;
|
|
|
+ }
|
|
|
+ return Infinity;
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.optimHeight = function() {
|
|
|
+ let max = Infinity;
|
|
|
+ for (let i =0; i < MAP_WIDTH; ++i)
|
|
|
+ max = Math.min(max, this.stackSize(i));
|
|
|
+ if (max !== Infinity) {
|
|
|
+ this.heightRemoved += max;
|
|
|
+ while (max-- > 0) {
|
|
|
+ this.data.shift();
|
|
|
+ this.dataBit.shift();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Arena.prototype.nextRock = async function(pieces, jetStream, displaySize, round) {
|
|
|
+ const colors = [ '\033[31m', '\033[32m', '\033[33m', '\033[35m', '\033[36m' ];
|
|
|
+ const chars = ['@', '!', '$', '%', '+', '=', '?', '#'];
|
|
|
+ let piece = pieces.pop();
|
|
|
+ let currentData = piece.map(i => i.split('').map(i => i === '#'));
|
|
|
+ this.current = {
|
|
|
+ data: piece.map(i => i.split('').map(i => i === '#')),
|
|
|
+ color: colors[Math.floor(Math.random() * colors.length)],
|
|
|
+ x: 2,
|
|
|
+ y: this.data.length +2,
|
|
|
+ c: chars[Math.floor(Math.random() * chars.length)],
|
|
|
+ height: 0,
|
|
|
+ width: 0
|
|
|
+ };
|
|
|
+ let currentBits = [];
|
|
|
+ for (let i of this.current.data) {
|
|
|
+ let b = 0x00;
|
|
|
+ for (let j =0; j < i.length; ++j)
|
|
|
+ b |= i[j]<<j;
|
|
|
+ currentBits.push(b);
|
|
|
+ }
|
|
|
+ this.current.data = currentBits;
|
|
|
+ this.current.height = this.current.data.length;
|
|
|
+ this.current.width = currentData[0].length;
|
|
|
+ do {
|
|
|
+ await this.move(jetStream.pop(), 0, displaySize);
|
|
|
+ } while (await this.move(0, -1, displaySize));
|
|
|
+ currentData
|
|
|
+ .map((line, y) =>
|
|
|
+ line.map((data, x) => data ? [x+this.current.x, this.current.height-y+this.current.y] : undefined))
|
|
|
+ .reduce((acc, i) => (acc || []).concat(i))
|
|
|
+ .filter(i => !!i)
|
|
|
+ .forEach(i => {
|
|
|
+ while (this.data.length <= i[1]) {
|
|
|
+ this.data.push([]);
|
|
|
+ this.dataBit.push(0x00);
|
|
|
+ }
|
|
|
+ this.data[i[1]][i[0]] = {
|
|
|
+ color: this.current.color,
|
|
|
+ c: this.current.c
|
|
|
+ };
|
|
|
+ this.dataBit[i[1]] |= (1 << i[0]);
|
|
|
+ });
|
|
|
+ this.current = null;
|
|
|
+ this.dejavu[pieces.pos+'x'+jetStream.pos] = { piece: pieces.pos, jetStream: jetStream.pos, index: round };
|
|
|
+ (round %500 === 0) && this.optimHeight();
|
|
|
+ await this.display(displaySize);
|
|
|
+}
|
|
|
+
|
|
|
+const SCREEN_SIZE = 60;
|
|
|
+//const ProgressBar = require('progress');
|
|
|
+
|
|
|
+async function main() {
|
|
|
+ let arena = new Arena();
|
|
|
+ let jetStream = null;
|
|
|
+ let pieces = new CircularBuffer([
|
|
|
+ ["####"],
|
|
|
+ [" # ", "###", " # "],
|
|
|
+ [" #", " #", "###"],
|
|
|
+ ["#", "#", "#", "#"],
|
|
|
+ ["##", "##"]
|
|
|
+ ]);
|
|
|
+ for await (let line of readline.createInterface({ input: process.stdin })) {
|
|
|
+ jetStream = new CircularBuffer(line.split('').map(i => i === '<' ? -1 : +1));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ let i =0;
|
|
|
+ for (; i < 2022; ++i)
|
|
|
+ await arena.nextRock(pieces, jetStream, 0, i);
|
|
|
+ console.log("Part 1", arena.heightRemoved + arena.data.length -1);
|
|
|
+ return;
|
|
|
+ //let Progress = new ProgressBar(':bar', { total: 1000000000000 });
|
|
|
+ for (; i < 1000000000000; ++i) {
|
|
|
+ arena.nextRock(pieces, jetStream, 0, i);
|
|
|
+ //Progress.tick();
|
|
|
+ }
|
|
|
+ console.log("\n\nPart 2", arena.heightRemoved + arena.data.length -1);
|
|
|
+};
|
|
|
+
|
|
|
+(main());
|
|
|
+
|