Tetris
Tetris
Why did the tetromino go to the gym?
To get fit in shape!
<!DOCTYPE html> <html> <head> <title>Tetris</title> <style> body { margin: 0; padding: 0; } canvas { display: block; margin: 0 auto; background-color: #111; } </style> </head> <body> <canvas id="tetris" width="240" height="400"></canvas> <script> const canvas = document.getElementById('tetris'); const context = canvas.getContext('2d'); // Draw a square on the canvas function drawSquare(x, y, color) { context.fillStyle = color; context.fillRect(x * 24, y * 24, 24, 24); context.strokeStyle = '#333'; context.strokeRect(x * 24, y * 24, 24, 24); } // Create the game board with an empty grid let board = []; for (let row = 0; row < 20; row++) { board[row] = []; for (let col = 0; col < 10; col++) { board[row][col] = '#111'; } } // Draw the game board function drawBoard() { for (let row = 0; row < 20; row++) { for (let col = 0; col < 10; col++) { drawSquare(col, row, board[row][col]); } } } drawBoard(); // Tetromino shapes and colors const tetrominos = [ ['#f00', '#0f0', '#00f', '#ff0'], // T ['#0f0', '#00f', '#f00', '#ff0'], // S ['#00f', '#f00', '#0f0', '#ff0'], // Z ['#ff0', '#00f', '#f00', '#0f0'], // L ['#f00', '#ff0', '#0f0', '#00f'], // J ['#0f0', '#f00', '#ff0', '#00f'], // O ['#00f', '#0f0', '#f00', '#ff0'] // I ]; // Tetromino shapes and their rotations const tetrominoShapes = [ [[0, 0, 0], [1, 1, 1], [0, 1, 0]], // T [[0, 2, 2], [2, 2, 0], [0, 0, 0]], // S [[3, 3, 0], [0, 3, 3], [0, 0, 0]], // Z [[4, 0, 0], [4, 4, 4], [0, 0, 0]], // L [[0, 0, 5], [5, 5, 5], [0, 0, 0]], // J [[6, 6], [6, 6]], // O [[0, 7, 0, 0], [0, 7, 0, 0], [0, 7, 0, 0], [0, 7, 0, 0]] // I ]; // Create a random tetromino shape and set its starting position let currentTetromino = { shape: tetrominoShapes[Math.floor(Math.random() * tetrominoShapes.length)], color: tetrominos[Math.floor(Math.random() * tetrominos.length)], x: 3, y: -2 }; // Draw a tetromino shape on the canvas function drawTetromino(tetromino, x, y) { for (let row = 0; row < tetromino.length; row++) { for (let col = 0; col < tetromino[row].length; col++) { if (tetromino[row][col]) { drawSquare(col + x, row + y, tetromino.color); } } } } // Clear the complete rows and move the rows above down function clearLines() { for (let row = 0; row < board.length; row++) { if (board[row].every(col => col !== '#111')) { board.splice(row, 1); board.unshift(['#111', '#111', '#111', '#111', '#111', '#111', '#111', '#111', '#111', '#111']); row--; } } } // Rotate a tetromino shape clockwise function rotateTetromino(tetromino) { let rotatedTetromino = []; for (let row = 0; row < tetromino.length; row++) { rotatedTetromino[row] = []; for (let col = 0; col < tetromino[row].length; col++) { rotatedTetromino[row][col] = tetromino[tetromino.length - col - 1][row]; } } return rotatedTetromino; } // Check if the new position of the tetromino is valid function isValidMove(tetromino, board, x, y) { for (let row = 0; row < tetromino.length; row++) { for (let col = 0; col < tetromino[row].length; col++) { if (tetromino[row][col]) { let newX = x + col; let newY = y + row; if (newX < 0 || newX >= board[0].length || newY >= board.length) { return false; } if (newY >= 0 && board[newY][newX] !== '#111') { return false; } } } } return true; } // Move the current tetromino down one row function moveTetrominoDown() { if (isValidMove(currentTetromino.shape, board, currentTetromino.x, currentTetromino.y + 1)) { currentTetromino.y++; drawBoard(); drawTetromino(currentTetromino, currentTetromino.x, currentTetromino.y); } else { // Add the current tetromino to the board for (let row = 0; row < currentTetromino.shape.length; row++) { for (let col = 0; col < currentTetromino.shape[row].length; col++) { if (currentTetromino.shape[row][col]) { board[currentTetromino.y + row][currentTetromino.x + col] = currentTetromino.color; } } } clearLines(); // Create a new tetromino and set its starting position currentTetromino = { shape: tetrominoShapes[Math.floor(Math.random() * tetrominoShapes.length)], color: tetrominos[Math.floor(Math.random() * tetrominos.length)], x: 3, y: -2 }; if (!isValidMove(currentTetromino.shape, board, currentTetromino.x, currentTetromino.y)) { // Game over context.fillStyle = '#fff'; context.font = 'bold 30px Arial'; context.fillText('Game Over!', 50, 200); } else { drawBoard(); drawTetromino(currentTetromino, currentTetromino.x, currentTetromino.y); } } } // Move the current tetromino left one column function moveTetrominoLeft() { if (isValidMove(currentTetromino.shape, board, currentTetromino.x - 1, currentTetromino.y)) { currentTetromino.x--; drawBoard(); drawTetromino(currentTetromino, currentTetromino.x, currentTetromino.y); } } // Move the current tetromino right one column function moveTetrominoRight() { if (isValidMove(currentTetromino.shape, board, currentTetromino.x + 1, currentTetromino.y)) { currentTetromino.x++; drawBoard(); drawTetromino(currentTetromino, currentTetromino.x, currentTetromino.y); } } // Rotate the current tetromino function rotateTetrominoOnce() { let rotatedTetromino = rotateTetromino(currentTetromino.shape); if (isValidMove(rotatedTetromino, board, currentTetromino.x, currentTetromino.y)) { currentTetromino.shape = rotatedTetromino; drawBoard(); drawTetromino(currentTetromino, currentTetromino.x, currentTetromino.y); } } // Keyboard controls for the game document.addEventListener('keydown', event => { switch (event.keyCode) { case 37: // Left arrow moveTetrominoLeft(); break; case 38: // Up arrow rotateTetrominoOnce(); break; case 39: // Right arrow moveTetrominoRight(); break; case 40: // Down arrow moveTetrominoDown(); break; } }); // Game loop setInterval(moveTetrominoDown, 500); </script> <p>Why did the tetromino go to the gym?<br> To get fit in shape!</p> </body> </html>