Created
August 12, 2025 02:10
-
-
Save geekygeeky/f565e25c76621b1a306a27d55dd96f92 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Tetris Game</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| background-color: #222; | |
| } | |
| canvas { | |
| border: 2px solid #fff; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="tetris" width="300" height="600"></canvas> | |
| <script> | |
| const canvas = document.getElementById("tetris"); | |
| const context = canvas.getContext("2d"); | |
| const rows = 20; | |
| const cols = 10; | |
| const blockSize = 30; | |
| context.scale(blockSize, blockSize); | |
| const tetrominos = [ | |
| { shape: [[1, 1, 1, 1]], color: "cyan" }, // I | |
| { shape: [[1, 1, 1], [0, 1, 0]], color: "yellow" }, // T | |
| { shape: [[1, 1], [1, 1]], color: "red" }, // O | |
| { shape: [[1, 1, 0], [0, 1, 1]], color: "green" }, // S | |
| { shape: [[0, 1, 1], [1, 1, 0]], color: "blue" }, // Z | |
| { shape: [[1, 0, 0], [1, 1, 1]], color: "orange" }, // L | |
| { shape: [[0, 0, 1], [1, 1, 1]], color: "purple" }, // J | |
| ]; | |
| let board = Array.from({ length: rows }, () => Array(cols).fill(null)); | |
| let currentPiece = randomTetromino(); | |
| let gameOver = false; | |
| document.addEventListener("keydown", handleKeyDown); | |
| function randomTetromino() { | |
| const tetromino = tetrominos[Math.floor(Math.random() * tetrominos.length)]; | |
| return { shape: tetromino.shape, color: tetromino.color, x: Math.floor(cols / 2) - 1, y: 0 }; | |
| } | |
| function rotate(piece) { | |
| const rotated = piece.shape[0].map((_, i) => piece.shape.map(row => row[i])); | |
| piece.shape = rotated.reverse(); | |
| } | |
| function handleKeyDown(e) { | |
| if (gameOver) return; | |
| if (e.key === "ArrowLeft") { | |
| if (canMove(currentPiece, -1, 0)) currentPiece.x -= 1; | |
| } else if (e.key === "ArrowRight") { | |
| if (canMove(currentPiece, 1, 0)) currentPiece.x += 1; | |
| } else if (e.key === "ArrowDown") { | |
| if (canMove(currentPiece, 0, 1)) currentPiece.y += 1; | |
| } else if (e.key === "ArrowUp") { | |
| rotate(currentPiece); | |
| if (!canMove(currentPiece, 0, 0)) rotate(currentPiece); // Undo if rotation is not valid | |
| } | |
| render(); | |
| } | |
| function canMove(piece, dx, dy) { | |
| for (let y = 0; y < piece.shape.length; y++) { | |
| for (let x = 0; x < piece.shape[y].length; x++) { | |
| if (piece.shape[y][x]) { | |
| const newX = piece.x + x + dx; | |
| const newY = piece.y + y + dy; | |
| if (newX < 0 || newX >= cols || newY >= rows || board[newY] && board[newY][newX]) { | |
| return false; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| function placePiece(piece) { | |
| for (let y = 0; y < piece.shape.length; y++) { | |
| for (let x = 0; x < piece.shape[y].length; x++) { | |
| if (piece.shape[y][x]) { | |
| board[piece.y + y][piece.x + x] = piece.color; | |
| } | |
| } | |
| } | |
| clearRows(); | |
| currentPiece = randomTetromino(); | |
| if (!canMove(currentPiece, 0, 0)) gameOver = true; | |
| } | |
| function clearRows() { | |
| for (let y = rows - 1; y >= 0; y--) { | |
| if (board[y].every(cell => cell !== null)) { | |
| board.splice(y, 1); | |
| board.unshift(Array(cols).fill(null)); | |
| } | |
| } | |
| } | |
| function render() { | |
| context.clearRect(0, 0, canvas.width, canvas.height); | |
| for (let y = 0; y < rows; y++) { | |
| for (let x = 0; x < cols; x++) { | |
| if (board[y][x]) { | |
| context.fillStyle = board[y][x]; | |
| context.fillRect(x, y, 1, 1); | |
| } | |
| } | |
| } | |
| for (let y = 0; y < currentPiece.shape.length; y++) { | |
| for (let x = 0; x < currentPiece.shape[y].length; x++) { | |
| if (currentPiece.shape[y][x]) { | |
| context.fillStyle = currentPiece.color; | |
| context.fillRect(currentPiece.x + x, currentPiece.y + y, 1, 1); | |
| } | |
| } | |
| } | |
| if (gameOver) { | |
| context.fillStyle = "white"; | |
| context.font = "30px Arial"; | |
| context.fillText("Game Over", 3, 10); | |
| } | |
| } | |
| function gameLoop() { | |
| if (gameOver) return; | |
| if (canMove(currentPiece, 0, 1)) { | |
| currentPiece.y += 1; | |
| } else { | |
| placePiece(currentPiece); | |
| } | |
| render(); | |
| setTimeout(gameLoop, 500); | |
| } | |
| gameLoop(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment