Tetris · deepseek-r1-0528
Build a playable Tetris on a canvas with all seven tetrominoes, rotation, line clears, increasing speed, a next-piece preview, and score.
This one-shot run produced no runnable artifact.
agent produced no index.html
The transcript below shows what the model did — read it to see why the one shot fell short.
transcript · 2 messages
Build a playable Tetris on a canvas with all seven tetrominoes, rotation, line clears, increasing speed, a next-piece preview, and score.
thinking
We are going to create a single `index.html` file that contains the entire Tetris game.
The game will be implemented using HTML5 Canvas and JavaScript.
Requirements:
- All seven tetrominoes (shapes: I, O, T, S, Z, J, L)
- Rotation (clockwise and counter-clockwise)
- Line clears (when a row is filled, remove it and shift above rows down)
- Increasing speed (as the player scores more, the game gets faster)
- Next-piece preview (show the next piece to the player)
- Score (keep track of the player's score)
We'll structure the code as follows:
- HTML: A canvas for the main board, a canvas for the next piece preview, and a div for the score.
- CSS: Basic styling to center the game and style the elements.
- JavaScript: The game logic.
Steps for the game logic:
1. Define the tetrominoes as arrays of their shapes in different rotations.
2. Set up the game board (a grid of cells).
3. Use a canvas to draw the board and the falling piece.
4. Implement the game loop:
- Move the falling piece down at intervals.
- Check for collisions and lock the piece when it hits the bottom or another piece.
- Check for completed lines and clear them.
- Update the score and level (which controls the speed).
5. Handle user input for moving and rotating the piece, and for starting/pausing the game.
6. Show the next piece in a preview area.
We'll write the entire game in one file.
Let's create the HTML structure first, then the CSS, then the JavaScript.
Important: The game must be self-contained in index.html, with no external resources.
We will create:
- A main container.
- A div to display the score and level.
- A canvas for the game board.
- A canvas for the next piece preview.
- A button to start the game.
We'll use the following constants and variables in JavaScript:
- The board dimensions (width: 10, height: 20, visible height might be less but we'll use 20)
- The size of each block (pixels)
- The current piece, next piece, position, rotation, etc.
The game will use requestAnimationFrame for smooth animation, and a game loop that updates at intervals.
We'll break the JavaScript code into functions:
- init(): Initialize the game state.
- startGame(): Start the game loop.
- gameLoop(): The main loop that updates the game state and draws the frame.
- drawBoard(): Draw the entire board and the falling piece.
- drawNextPiece(): Draw the next piece in the preview canvas.
- handleInput(): Handle keyboard input.
We'll also define functions for:
- createPiece(): Generate a random tetromino.
- movePiece(): Move the piece left/right/down.
- rotatePiece(): Rotate the current piece if possible.
- clearLines(): Check for completed lines and clear them.
- collision detection.
Since we are writing everything in one file, we will include the script in a <script> tag and the CSS in a <style> tag.
Let's write the index.html content.
I'll create a self-contained Tetris game in a single HTML file. Here's the implementation: html <!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 { font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background: #1a1a2e; margin: 0; padding: 20px; } .game-container { display: flex; gap: 30px; background: #16213e; padding: 25px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); } canvas { background: #0f3460; border: 3px solid #e94560; border-radius: 8px; } .side-panel { color: white; display: flex; flex-direction: column; gap: 15px; } .info-box { background: #0f3460; border-radius: 8px; padding: 15px; text-align: center; } h2 { margin: 0 0 10px; color: #e94560; font-size: 1.5em; } .controls { margin-top: 10px; font-size: 14px; line-height: 1.4; } #next-piece { width: 150px; height: 150px; background: #0f3460; border: 2px solid #e94560; border-radius: 8px; } button { background: #e94560; color: white; border: none; padding: 8px 15px; border-radius: 5px; cursor: pointer; font-weight: bold; margin-top: 10px; transition: background 0.3s; } button:hover { background: #ff6b81; } </style> </head> <body> <div class="game-container"> <div class="side-panel"> <div class="info-box"> <h2>SCORE</h2> <div id="score">0</div> </div> <div class="info-box"> <h2>LEVEL</h2> <div id="level">1</div> </div> <div class="info-box"> <h2>NEXT</h2> <canvas id="next-piece" width="150" height="150"></canvas> </div> <div class="info-box"> <h2>CONTROLS</h2> <div class="controls"> <p>← → : Move</br> ↑ : Rotate</br> ↓ : Soft Drop</br> Space : Hard Drop</p> </div> </div> <div class="info-box"> <button id="start-pause">Start Game</button> <button id="restart">Restart</button> </div> </div> <canvas id="tetris" width="300" height="600"></canvas> </div> <script> // Constants and game variables const COLS = 10; const ROWS = 20; const BLOCK_SIZE = 30; const COLORS = [ 'cyan', // I piece 'blue', // J piece 'orange', // L piece 'yellow', // O piece 'green', // S piece 'red', // Z piece 'purple' // T piece ]; // Tetromino shapes (all rotations) const SHAPES = [ // I piece [ [[0,0],[1,0],[2,0],[3,0]], [[0,0],[0,1],[0,2],[0,3]] ], // J piece [ [[0,0],[1,0],[2,0],[2,1]], [[1,0],[1,1],[1,2],[0,2]], [[0,0],[0,1],[1,1],[2,1]], [[1,0],[2,0],[1,1],[1,2]] ], // L piece [ [[0,0],[1,0],[2,0],[0,1]], [[0,0],[1,0],[1,1],[1,2]], [[2,0],[0,1],[1,1],[2,1]], [[1,0],[1,1],[1,2],[2,2]] ], // O piece (only one rotation) [ [[0,0],[1,0],[0,1],[1,1]] ], // S piece [ [[1,0],[2,0],[0,1],[1,1]], [[0,0],[0,1],[1,1],[1,2]] ], // Z piece [ [[0,0],[1,0],[1,1],[2,1]], [[1,0],[0,1],[1,1],[0,2]] ], // T piece [ [[1,0],[0,1],[1,1],[2,1]], [[1,0],[1,1],[2,1],[1,2]], [[0,1],[1,1],[2,1],[1,2]], [[1,0],[0,1],[1,1],[1,2]] ] ]; const canvas = document.getElementById('tetris'); const ctx = canvas.getContext('2d'); const nextCtx = document.getElementById('next-piece').getContext('2d'); let board = []; let currentPiece = null; let nextPiece = null; let score = 0; let level = 1; let dropInterval = null; let gameActive = false; let dropSpeed = 800; // ms // Initialize the game board function createBoard() { board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); } // Create a random piece function createPiece() { const pieceType = Math.floor(Math.random() * SHAPES.length); const rotations = SHAPES[pieceType]; const rotationIdx = Math.floor(Math.random() * rotations.length); return { type: pieceType, shape: rotations[rotationIdx], rotation: rotationIdx, x: Math.floor(COLS / 2) - 1, y: -2, // Start just above the board color: COLORS[pieceType] }; } // Rotate the current piece function rotatePiece() { if (!currentPiece) return; const originalRotation = currentPiece.rotation; const rotations = SHAPES[currentPiece.type]; currentPiece.rotation = (currentPiece.rotation + 1) % rotations.length; currentPiece.shape = rotations[currentPiece.rotation]; // If rotation causes collision, revert the rotation if (collision()) { currentPiece.rotation = originalRotation; currentPiece.shape = rotations[originalRotation]; } } // Draw the board and current piece function drawBoard() { // Clear the canvas ctx.fillStyle = '#0f3460'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw board cells for (let row = 0; row < ROWS; row++) { for (let col = 0; col < COLS; col++) { if (board[row][col]) { drawBlock(col, row, board[row][col]); } } } // Draw current piece if (currentPiece) { currentPiece.shape.forEach(row => { const x = currentPiece.x + row[0]; const y = currentPiece.y + row[1]; if (y >= 0) { drawBlock(x, y, currentPiece.color); } }); } } // Draw next piece preview function drawNextPiece() { nextCtx.fillStyle = '#0f3460'; nextCtx.fillRect(0, 0, nextCtx.canvas.width, nextCtx.canvas.height); if (nextPiece) { // Position next piece in the center of the preview nextPiece.shape.forEach(row => { drawBlock( nextPiece.x - 2 + row[0] + 2, nextPiece.y + row[1] + 2, nextPiece.color, nextCtx, nextCtx.canvas.width / 6 ); }); } } // Draw a single block in the world function drawBlock(x, y, color, context = ctx, size = BLOCK_SIZE) { const blockSize = size; const padding = size / 12; const innerPad = size / 20; context.fillStyle = color; context.fillRect(x * blockSize, y * blockSize, blockSize, blockSize); context.fillStyle = 'rgba(255, 255, 255, 0.3)'; context.fillRect( x * blockSize + padding, y * blockSize + padding, blockSize - 2 * padding, blockSize - 2 * padding ); } // Move the current piece down function drop() { if (!currentPiece) return; currentPiece.y++; if (collision()) { currentPiece.y--; lockPiece(); clearLines(); // Create next piece currentPiece = nextPiece; currentPiece.x = Math.floor(COLS / 2) - 1; currentPiece.y = -2; // Create new next piece nextPiece = createPiece(); drawNextPiece(); } drawBoard(); } // Move piece horizontally function move(dir) { currentPiece.x += dir; if (collision()) currentPiece.x -= dir; drawBoard(); } // Hard drop (drop to bottom) function hardDrop() { while (!collision()) { currentPiece.y++; } currentPiece.y--; drop(); // Lock piece } // Check for collisions function collision() { return currentPiece.shape.some(row => { const x = currentPiece.x + row[0]; const y = currentPiece.y + row[1]; // Collision with walls or floor if (x < 0 || x >= COLS || y >= ROWS) return true; // Collision with existing blocks (ignore blocks above the board) if (y >= 0 && board[y][x]) return true; return false; }); } // Lock piece in place and add to board function lockPiece() { currentPiece.shape.forEach(row => { const x = currentPiece.x + row[0]; const y = currentPiece.y + row[1]; // Only add blocks that are on the board if (y >= 0) { board[y][x] = currentPiece.color; } }); } // Clear completed lines function clearLines() { let linesCleared = 0; for (let row = ROWS - 1; row >= 0; row--) { // Check if line is complete if (board[row].every(cell => cell !== 0)) { // Remove the completed line board.splice(row, 1); // Add new empty line at the top board.unshift(Array(COLS).fill(0)); linesCleared++; row++; // Re-check this row position after shift } } if (linesCleared > 0) { // Update score score += [0, 100, 300, 500, 800][linesCleared] * level; document.getElementById('score').textContent = score; // Increase level every 1000 points const newLevel = Math.floor(score / 1000) + 1; if (newLevel > level) { level = newLevel; document.getElementById('level').textContent = level; // Increase speed clearInterval(dropInterval); dropSpeed = Math.max(50, 800 - (level - 1) * 70); if (gameActive) { dropInterval = setInterval(drop, dropSpeed); } } } } // Initialize game state function initGame() { createBoard(); if (!nextPiece) nextPiece = createPiece(); currentPiece = createPiece(); nextPiece = createPiece(); drawBoard(); drawNextPiece(); score = 0; level = 1; document.getElementById('score').textContent = score; document.getElementById('level').textContent = level; } // Start or pause the game function toggleGame() { if (!gameActive) { document.getElementById('start-pause').textContent = 'Pause'; if (!currentPiece) initGame(); gameActive = true; clearInterval(dropInterval); dropInterval = setInterval(drop, dropSpeed); } else { document.getElementById('start-pause').textContent = 'Resume'; gameActive = false; clearInterval(dropInterval); } } // Keyboard controls document.addEventListener('keydown', e => { if (!gameActive) return; switch (e.key) { case 'ArrowLeft': move(-1); break; case 'ArrowRight': move(1); break; case 'ArrowDown': drop(); break; case 'ArrowUp': rotatePiece(); drawBoard(); break; case ' ': hardDrop(); break; } }); // Button handlers document.getElementById('start-pause').addEventListener('click', toggleGame); document.getElementById('restart').addEventListener('click', () => { if (gameActive) toggleGame(); initGame(); }); // Start the game with "Start Game" button pressed document.getElementById('start-pause').click(); </script> </body> </html> This implementation includes: 1. All seven Tetris pieces with distinct colors 2. Rotation using the UP arrow key 3. Horizontal movement with LEFT/RIGHT arrows 4. Soft (↓) and hard drop (SPACE) 5. Line clearing mechanics 6. Increasing speed based on level progression 7. Next-piece preview 8. Score display with increasing difficulty 9. Start/pause and restart functionality 10. Responsive controls display 11. Colorful block-based visual design The game board is 10×20 cells with a block size of 30px. Each level increases after every 1000 points, making the falling pieces faster. To play: 1. Click "Start Game" 2. Use arrow keys to move/rotate pieces 3. Clear rows to get points 4. The game speeds up as your score increases and level progresses 5. Try to survive as long as possible!
TAKE IT TO CODE
This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.