| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- 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());
|