const chalk = require('chalk') var cursorX = 0; var cursorY = 0; var placing = getRandomBlock(false); var board = []; var score = 0; for (var y = 0; y < 7; y++) { board.push([]); for (var x = 0; x < 7; x++) { board[y].push(0); } } const blocksToPlace = 25; const solidRows = 3; for (var i = 0;i < solidRows;i++){ for (var x = 0; x < 7; x++) { dropBlock(-2, x); } } for (var i = 0; i < blocksToPlace; i++) { dropBlock(getRandomBlock(true), Math.floor(Math.random() * 7)); } const readline = require('readline'); readline.emitKeypressEvents(process.stdin); process.stdin.setRawMode(true); process.stdin.on('keypress', (str, key) => { if (key.ctrl && key.name === 'c') { process.exit(); } else { switch (key.name) { case 'left': cursorX = Math.max(0, cursorX - 1); break; case 'right': cursorX = Math.min(6, cursorX + 1); break; case 'up': cursorY = Math.max(0, cursorY - 1); break; case 'down': cursorY = Math.min(6, cursorY + 1); break; case 'enter': case 'return': const successfullyDropped = dropBlock(placing, cursorX); if(successfullyDropped) placing = getRandomBlock(false); } paintBoard(); } }); console.log('Press any key...'); function getRandomBlock(canBeSolid) { var value = Math.floor(Math.random() * (canBeSolid ? 10 : 8)) - (canBeSolid ? 2 : 0); if(value === 0) return getRandomBlock(canBeSolid); //value cannot be 0, try again. return value; } function dropBlock(value, column) { //find the lowest point it can sit. var yPos = -1; for (var y = 6; y >= 0; y--) { if (board[y][column] === 0) { yPos = y; break; } } if (yPos === -1) { //cannot place block, column full return false; } board[yPos][column] = value; var comboMultiplier = 1; var pointsEarned = 0; do { pointsEarned = detectScoring(); score += pointsEarned * comboMultiplier; shakedownBoard(); comboMultiplier *= 2; } while (pointsEarned > 0); return true; } function detectScoring() { //check vertical //how tall is each stack? var toPop = []; for (var x = 0; x < 7; x++) { var stackHeight = 7; for (var y = 6; y >= 0; y--) { if (board[y][x] === 0) { stackHeight = 6 - y; break; } } if (stackHeight <= 0) continue; //are there any in the stack that match the stack height var poppingWillOccur = false; for (var y = 0; y < 7; y++) { if (board[y][x] === stackHeight) { toPop.push({ x: x, y: y }); poppingWillOccur = true; } } if (poppingWillOccur) { //break blank blocks by one level for (var y = 0; y < 7; y++) { if (board[y][x] < 0) { toPop.push({ x: x, y: y }); } } } } //check horizontal groups for (var y = 6; y >= 0; y--) { //start from the bottom up const groups = [[]] var buildingGroupIndex = 0; for (var x = 0; x < 7; x++) { if (groups[buildingGroupIndex].length === 0) { //if current group is empty if (board[y][x] === 0) continue; groups[buildingGroupIndex].push({ x: x, y: y, v: board[y][x] }); } else { //current group has at least one element in it if (board[y][x] === 0) { if (x < 6) { //if we're not in the last column, create a new group for the next stuff buildingGroupIndex++; groups.push([]); } continue; } else { groups[buildingGroupIndex].push({ x: x, y: y, v: board[y][x] }); } } } for (var g = 0; g < groups.length; g++) { var popWillOccurrInGroup = false; for (var j = 0; j < groups[g].length; j++) { if (groups[g].length === groups[g][j].v) { popWillOccurrInGroup = true; toPop.push({ x: groups[g][j].x, y: groups[g][j].y }) } } if (popWillOccurrInGroup) { for (var j = 0; j < groups[g].length; j++) { if (groups[g][j].v < 0) { toPop.push({ x: groups[g][j].x, y: groups[g][j].y }) } } } } } var points = 0; for (var j = 0; j < toPop.length; j++) { const value = board[toPop[j].y][toPop[j].x] if (value < 0) { var newValue = value + 1; if (newValue === 0) { newValue = Math.floor(Math.random() * 7) + 1 } board[toPop[j].y][toPop[j].x] = newValue; } else { points += board[toPop[j].y][toPop[j].x]; board[toPop[j].y][toPop[j].x] = 0; } } return points; } function shakedownBoard() { for (var x = 0; x < 7; x++) { //loop through each column for (var y = 6; y >= 0; y--) { //check to see if we can push this element down if (y === 6) continue; // can't push any further than bottom const below = board[y + 1][x]; if (below === 0) { //airspace directly below //get top of stack index and swap it with current. var newPos = -1; for (var a = 6; a >= 0; a--) { if (board[a][x] === 0) { newPos = a; break; } } if (newPos === -1) { //cannot place block, column full system.exit(); // shouldn't ever happen in a shakedown. } //do the swap board[newPos][x] = board[y][x]; board[y][x] = 0; } } } } function getBlockColor(value){ switch(value){ case 7: return chalk.blue; case 6: return chalk.cyanBright; case 5: return chalk.magenta; case 4: return chalk.red; case 3: return chalk.yellow; case 2: return chalk.yellowBright; case 1: return chalk.greenBright; case 0: return chalk.black; case -1: return chalk.white; case -2: return chalk.white; } } function paintBoard() { console.clear(); //paint the placing row; for(var x = 0;x < 7;x++) if(x === cursorX) process.stdout.write(`${placing} `); else process.stdout.write(' '); //semi solid process.stdout.write('\n'); for (var y = 0; y < 7; y++) { for (var x = 0; x < 7; x++) { var charToPrint = ' '; switch (board[y][x]) { case 0: charToPrint = ' '; break; case -1: charToPrint = '\u2591'; //semi solid break; case -2: charToPrint = '\u2593'; // dark block break; default: charToPrint = `${board[y][x]}` } process.stdout.write(`${getBlockColor(board[y][x])(charToPrint)} `) } process.stdout.write('\n'); } process.stdout.write('-------------\n\nScore: ' + score + '\n'); } paintBoard();