oneshotlm
Compare all models on this prompt →

2048 · mistral-medium-3.1

Build a playable 2048 game with arrow-key tile sliding and merging, smooth animations, a score, and win and lose states.

⛨ sandboxed Open in new tab ↗
transcript · 8 messages
user

Build a playable 2048 game with arrow-key tile sliding and merging, smooth animations, a score, and win and lose states.

assistant
write index.html (16152 bytes)
toolResult

Successfully wrote 16152 bytes to index.html

assistant
edit index.html (10767 bytes)
toolResult

Validation failed for tool "edit": - edits: must have required properties edits Received arguments: { "path": "index.html", "content": " while (currentRow > 0 && grid[currentRow - 1][col] === 0) {\n // Move tile up\n grid[currentRow - 1][col] = grid[currentRow][col];\n grid[currentRow][col] = 0;\n currentRow--;\n moved = true;\n }\n \n // Check if we can merge with the tile above\n if (currentRow > 0 && grid[currentRow - 1][col] === grid[currentRow][col]) {\n // Merge tiles\n grid[currentRow - 1][col] *= 2;\n score += grid[currentRow - 1][col];\n grid[currentRow][col] = 0;\n \n // Update best score\n if (score > bestScore) {\n bestScore = score;\n bestScoreElement.textContent = bestScore;\n localStorage.setItem('bestScore', bestScore);\n }\n \n scoreElement.textContent = score;\n moved = true;\n }\n }\n }\n }\n \n return moved;\n }\n \n // Move tiles down\n function moveDown() {\n let moved = false;\n \n for (let col = 0; col < GRID_SIZE; col++) {\n for (let row = GRID_SIZE - 2; row >= 0; row--) {\n if (grid[row][col] !== 0) {\n let currentRow = row;\n \n // Move tile down as far as possible\n while (currentRow < GRID_SIZE - 1 && grid[currentRow + 1][col] === 0) {\n // Move tile down\n grid[currentRow + 1][col] = grid[currentRow][col];\n grid[currentRow][col] = 0;\n currentRow++;\n moved = true;\n }\n \n // Check if we can merge with the tile below\n if (currentRow < GRID_SIZE - 1 && grid[currentRow + 1][col] === grid[currentRow][col]) {\n // Merge tiles\n grid[currentRow + 1][col] *= 2;\n score += grid[currentRow + 1][col];\n grid[currentRow][col] = 0;\n \n // Update best score\n if (score > bestScore) {\n bestScore = score;\n bestScoreElement.textContent = bestScore;\n localStorage.setItem('bestScore', bestScore);\n }\n \n scoreElement.textContent = score;\n moved = true;\n }\n }\n }\n }\n \n return moved;\n }\n \n // Move tiles left\n function moveLeft() {\n let moved = false;\n \n for (let row = 0; row < GRID_SIZE; row++) {\n for (let col = 1; col < GRID_SIZE; col++) {\n if (grid[row][col] !== 0) {\n let currentCol = col;\n \n // Move tile left as far as possible\n while (currentCol > 0 && grid[row][currentCol - 1] === 0) {\n // Move tile left\n grid[row][currentCol - 1] = grid[row][currentCol];\n grid[row][currentCol] = 0;\n currentCol--;\n moved = true;\n }\n \n // Check if we can merge with the tile to the left\n if (currentCol > 0 && grid[row][currentCol - 1] === grid[row][currentCol]) {\n // Merge tiles\n grid[row][currentCol - 1] *= 2;\n score += grid[row][currentCol - 1];\n grid[row][currentCol] = 0;\n \n // Update best score\n if (score > bestScore) {\n bestScore = score;\n bestScoreElement.textContent = bestScore;\n localStorage.setItem('bestScore', bestScore);\n }\n \n scoreElement.textContent = score;\n moved = true;\n }\n }\n }\n }\n \n return moved;\n }\n \n // Move tiles right\n function moveRight() {\n let moved = false;\n \n for (let row = 0; row < GRID_SIZE; row++) {\n for (let col = GRID_SIZE - 2; col >= 0; col--) {\n if (grid[row][col] !== 0) {\n let currentCol = col;\n \n // Move tile right as far as possible\n while (currentCol < GRID_SIZE - 1 && grid[row][currentCol + 1] === 0) {\n // Move tile right\n grid[row][currentCol + 1] = grid[row][currentCol];\n grid[row][currentCol] = 0;\n currentCol++;\n moved = true;\n }\n \n // Check if we can merge with the tile to the right\n if (currentCol < GRID_SIZE - 1 && grid[row][currentCol + 1] === grid[row][currentCol]) {\n // Merge tiles\n grid[row][currentCol + 1] *= 2;\n score += grid[row][currentCol + 1];\n grid[row][currentCol] = 0;\n \n // Update best score\n if (score > bestScore) {\n bestScore = score;\n bestScoreElement.textContent = bestScore;\n localStorage.setItem('bestScore', bestScore);\n }\n \n scoreElement.textContent = score;\n moved = true;\n }\n }\n }\n }\n \n return moved;\n }\n \n // Show game message\n function showGameMessage(title, text) {\n messageTitle.textContent = title;\n messageText.textContent = text;\n gameMessage.style.display = 'flex';\n }\n \n // Handle keyboard input\n function handleKeyDown(e) {\n if (gameOver) return;\n \n switch (e.key) {\n case 'ArrowUp':\n move('up');\n break;\n case 'ArrowDown':\n move('down');\n break;\n case 'ArrowLeft':\n move('left');\n break;\n case 'ArrowRight':\n move('right');\n break;\n }\n }\n \n // Handle touch input\n function handleTouchStart(e) {\n if (gameOver) return;\n \n const touch = e.touches[0];\n touchStartX = touch.clientX;\n touchStartY = touch.clientY;\n e.preventDefault();\n }\n \n function handleTouchMove(e) {\n if (gameOver) return;\n \n if (!touchStartX || !touchStartY) return;\n \n const touch = e.touches[0];\n const touchEndX = touch.clientX;\n const touchEndY = touch.clientY;\n \n const diffX = touchStartX - touchEndX;\n const diffY = touchStartY - touchEndY;\n \n // Determine swipe direction\n if (Math.abs(diffX) > Math.abs(diffY)) {\n // Horizontal swipe\n if (diffX > 0) {\n // Left swipe\n move('left');\n } else {\n // Right swipe\n move('right');\n }\n } else {\n // Vertical swipe\n if (diffY > 0) {\n // Up swipe\n move('up');\n } else {\n // Down swipe\n move('down');\n }\n }\n \n // Reset touch coordinates\n touchStartX = null;\n touchStartY = null;\n e.preventDefault();\n }\n \n // Initialize touch coordinates\n let touchStartX = null;\n let touchStartY = null;\n \n // Event listeners\n document.addEventListener('keydown', handleKeyDown);\n gameContainer.addEventListener('touchstart', handleTouchStart, { passive: false });\n gameContainer.addEventListener('touchmove', handleTouchMove, { passive: false });\n restartButton.addEventListener('click', initGame);\n \n // Start the game\n initGame();\n });\n </script>\n</body>\n</html>" }

assistant
edit {"path":"index.html","edits":[{"oldText":" </div>\n </div>\n \n <p class=\"instructions\">","newText":" </div>\n <
toolResult

Successfully replaced 1 block(s) in index.html.

assistant

The complete 2048 game is now ready in `index.html`. The file includes: - **Game Board**: 4×4 grid with smooth animations for tile movement and merging - **Controls**: Arrow keys (or swipe on touch devices) to slide tiles - **Scoring**: Tracks current score and best score (persisted in localStorage) - **Game States**: Win detection (2048 tile), lose detection (no valid moves), and restart option - **Visuals**: Color-coded tiles, animations for new/merged tiles, and responsive design You can open the file in any modern browser to play. No network connection or external resources are required.

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelmistral-medium-3.1
vendorMistral AI
harnesspi-agent
generated2026-08-01

EVALUATION

3/5 partial

2048 grid renders and arrow keys slide tiles, but WASD/click/drag/wheel produce no reaction and no score increased.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion0.0%
on click0.0%
on drag0.0%
on wheel0.0%
on enter + space0.0%
on arrow keys5.3%
on w/a/s/d0.0%
frame spread24.5 / 255
console errors0
js errors none

METRICS

runtime99.2s
tokens in30k
tokens out10k
cached27k
cost / run$0.0232