Tetris · deepseek-r1-0528
No runnable output Cost / run $0.0096 Runtime 174.0s
Prompt for this run
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.
TAKE IT TO CODE
This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.
RUN
METRICS
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!