Train snakeOne-line
Claude Haiku 4.5
by AnthropicReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 36.9 s
- Cost
- $0.069
- Output tokens
- 13,634
- Spent thinking
- 9,452 tokens
- Speed
- 383.4 tok/s
- Console errors
- 0
- First token after
- 1.4 s
- First visible text after
- 33.1 s
- Prompt tokens
- 411
- Code size
- 13.5 KB
- Finish reason
- stop
- Served by
- Amazon Bedrock
- Model id
anthropic/claude-haiku-4.5- Reasoning sent
{"enabled":true}- Max output
- 64,000 tokens
- Generated
- Nov 10, 2026
What it was asked
The prompt
“make me a snake game where the snake is a little train with a locomotive and colorful wagons, picking up passengers waiting on the platform”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task. Output rules: - Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block. - Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task. - Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw. - The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar. - Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction. - Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session. - Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing. - The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message. - The code must run with zero errors in the console of the latest Chrome.
Code run-1.html · 410 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Train Snake Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: Arial, sans-serif;
}
#gameContainer {
position: relative;
background: #1a1a2e;
border: 4px solid #16c784;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
canvas {
display: block;
background: linear-gradient(0deg, #0f3460 0%, #1a1a2e 100%);
}
#startMessage {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: #16c784;
padding: 30px 50px;
border-radius: 10px;
text-align: center;
font-size: 24px;
font-weight: bold;
z-index: 100;
animation: pulse 1s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
#score {
position: absolute;
top: 20px;
left: 20px;
color: #16c784;
font-size: 24px;
font-weight: bold;
z-index: 10;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
#gameOver {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.95);
color: #ff6b6b;
padding: 40px 60px;
border-radius: 10px;
text-align: center;
z-index: 200;
display: none;
}
#gameOver h1 {
font-size: 36px;
margin-bottom: 20px;
}
#gameOver p {
font-size: 20px;
margin: 10px 0;
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="gameCanvas"></canvas>
<div id="score">Passengers: 0</div>
<div id="startMessage">Click or press a key to start</div>
<div id="gameOver">
<h1>Game Over!</h1>
<p id="finalScore">Passengers: 0</p>
<p>Click or press a key to play again</p>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gameOverScreen = document.getElementById('gameOver');
const scoreDisplay = document.getElementById('score');
const startMessage = document.getElementById('startMessage');
const finalScoreDisplay = document.getElementById('finalScore');
// Responsive canvas size
function resizeCanvas() {
const width = Math.min(800, window.innerWidth - 40);
const height = Math.min(600, window.innerHeight - 40);
canvas.width = width;
canvas.height = height;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Game variables
const GRID_SIZE = 30;
let train = [];
let direction = { x: 1, y: 0 };
let nextDirection = { x: 1, y: 0 };
let passengers = [];
let score = 0;
let gameRunning = false;
let gameOverFlag = false;
let autoPlay = true;
let frameCount = 0;
const WAGON_COLORS = [
'#FF6B6B', '#4ECDC4', '#FFE66D', '#95E1D3',
'#C7CEEA', '#FF8B94', '#B4A7D6', '#73A580'
];
class Passenger {
constructor() {
this.gridX = Math.floor(Math.random() * (canvas.width / GRID_SIZE));
this.gridY = Math.floor(Math.random() * (canvas.height / GRID_SIZE));
}
draw() {
const x = this.gridX * GRID_SIZE;
const y = this.gridY * GRID_SIZE;
ctx.fillStyle = '#e8c547';
ctx.fillRect(x + 5, y + GRID_SIZE - 8, GRID_SIZE - 10, 8);
ctx.fillStyle = '#ffd700';
ctx.fillRect(x + GRID_SIZE/2 - 4, y + 8, 8, 8);
ctx.fillRect(x + GRID_SIZE/2 - 5, y + 16, 10, 10);
}
}
function initGame() {
const gridW = Math.floor(canvas.width / GRID_SIZE);
const gridH = Math.floor(canvas.height / GRID_SIZE);
train = [
{ x: Math.floor(gridW / 2), y: Math.floor(gridH / 2) },
{ x: Math.floor(gridW / 2) - 1, y: Math.floor(gridH / 2) },
{ x: Math.floor(gridW / 2) - 2, y: Math.floor(gridH / 2) }
];
direction = { x: 1, y: 0 };
nextDirection = { x: 1, y: 0 };
passengers = [];
score = 0;
gameRunning = true;
gameOverFlag = false;
frameCount = 0;
for (let i = 0; i < 3; i++) {
passengers.push(new Passenger());
}
updateScore();
gameOverScreen.style.display = 'none';
startMessage.style.display = 'block';
}
function updateScore() {
scoreDisplay.textContent = `Passengers: ${score}`;
}
function drawLocomotive(x, y) {
ctx.fillStyle = '#FF4444';
ctx.fillRect(x + 2, y + 4, GRID_SIZE - 4, GRID_SIZE - 8);
ctx.fillStyle = '#000';
ctx.fillRect(x + GRID_SIZE - 10, y + 6, 8, 10);
ctx.fillStyle = '#87CEEB';
ctx.fillRect(x + GRID_SIZE - 9, y + 7, 6, 8);
ctx.fillStyle = '#333';
ctx.fillRect(x + 6, y + 2, 4, 6);
ctx.fillStyle = '#999';
ctx.fillRect(x + 5, y + 1, 6, 2);
ctx.fillStyle = '#222';
ctx.beginPath();
ctx.moveTo(x + 2, y + 8);
ctx.lineTo(x + 2, y + 22);
ctx.lineTo(x + 0, y + 20);
ctx.lineTo(x + 0, y + 10);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#111';
ctx.beginPath();
ctx.arc(x + 6, y + GRID_SIZE - 1, 3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(x + GRID_SIZE - 6, y + GRID_SIZE - 1, 3, 0, Math.PI * 2);
ctx.fill();
}
function drawWagon(x, y, colorIndex) {
const color = WAGON_COLORS[colorIndex % WAGON_COLORS.length];
ctx.fillStyle = color;
ctx.fillRect(x + 2, y + 4, GRID_SIZE - 4, GRID_SIZE - 8);
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.strokeRect(x + 2, y + 4, GRID_SIZE - 4, GRID_SIZE - 8);
ctx.fillStyle = '#87CEEB';
ctx.fillRect(x + 5, y + 7, 5, 5);
ctx.fillRect(x + 14, y + 7, 5, 5);
ctx.fillStyle = '#111';
ctx.beginPath();
ctx.arc(x + 6, y + GRID_SIZE - 1, 3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(x + GRID_SIZE - 6, y + GRID_SIZE - 1, 3, 0, Math.PI * 2);
ctx.fill();
}
function drawTrain() {
for (let i = train.length - 1; i >= 0; i--) {
const segment = train[i];
const x = segment.x * GRID_SIZE;
const y = segment.y * GRID_SIZE;
if (i === 0) {
drawLocomotive(x, y);
} else {
drawWagon(x, y, i - 1);
}
}
}
function update() {
if (!gameRunning) return;
frameCount++;
// Auto-play logic
if (autoPlay && frameCount % 15 === 0) {
const head = train[0];
const closest = passengers.reduce((a, b) => {
const distA = Math.abs(head.x - a.gridX) + Math.abs(head.y - a.gridY);
const distB = Math.abs(head.x - b.gridX) + Math.abs(head.y - b.gridY);
return distA < distB ? a : b;
});
if (head.x < closest.gridX && direction.x === 0) nextDirection = { x: 1, y: 0 };
else if (head.x > closest.gridX && direction.x === 0) nextDirection = { x: -1, y: 0 };
else if (head.y < closest.gridY && direction.y === 0) nextDirection = { x: 0, y: 1 };
else if (head.y > closest.gridY && direction.y === 0) nextDirection = { x: 0, y: -1 };
}
// Move every 8 frames
if (frameCount % 8 === 0) {
direction = nextDirection;
const head = train[0];
const gridW = Math.floor(canvas.width / GRID_SIZE);
const gridH = Math.floor(canvas.height / GRID_SIZE);
const newHead = {
x: head.x + direction.x,
y: head.y + direction.y
};
// Wall collision
if (newHead.x < 0 || newHead.x >= gridW ||
newHead.y < 0 || newHead.y >= gridH) {
endGame();
return;
}
// Self collision
for (let segment of train) {
if (segment.x === newHead.x && segment.y === newHead.y) {
endGame();
return;
}
}
train.unshift(newHead);
// Check passenger collision
let passengerIdx = -1;
for (let i = 0; i < passengers.length; i++) {
if (passengers[i].gridX === newHead.x && passengers[i].gridY === newHead.y) {
passengerIdx = i;
break;
}
}
if (passengerIdx !== -1) {
passengers.splice(passengerIdx, 1);
passengers.push(new Passenger());
score++;
updateScore();
} else {
train.pop();
}
}
}
function endGame() {
gameRunning = false;
gameOverFlag = true;
gameOverScreen.style.display = 'block';
finalScoreDisplay.textContent = `Passengers: ${score}`;
}
function draw() {
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
ctx.lineWidth = 0.5;
for (let i = 0; i < canvas.width; i += GRID_SIZE) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, canvas.height);
ctx.stroke();
}
for (let i = 0; i < canvas.height; i += GRID_SIZE) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(canvas.width, i);
ctx.stroke();
}
for (let passenger of passengers) {
passenger.draw();
}
drawTrain();
}
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
// Input handling
document.addEventListener('keydown', (e) => {
if (autoPlay && !gameOverFlag) {
autoPlay = false;
startMessage.style.display = 'none';
handleDirection(e.key);
} else if (gameOverFlag) {
autoPlay = true;
initGame();
} else if (!autoPlay && gameRunning) {
handleDirection(e.key);
}
});
function handleDirection(key) {
if (key === 'ArrowUp' || key === 'w' || key === 'W') {
if (direction.y === 0) nextDirection = { x: 0, y: -1 };
} else if (key === 'ArrowDown' || key === 's' || key === 'S') {
if (direction.y === 0) nextDirection = { x: 0, y: 1 };
} else if (key === 'ArrowLeft' || key === 'a' || key === 'A') {
if (direction.x === 0) nextDirection = { x: -1, y: 0 };
} else if (key === 'ArrowRight' || key === 'd' || key === 'D') {
if (direction.x === 0) nextDirection = { x: 1, y: 0 };
}
}
canvas.addEventListener('click', () => {
if (autoPlay && !gameOverFlag) {
autoPlay = false;
startMessage.style.display = 'none';
} else if (gameOverFlag) {
autoPlay = true;
initGame();
}
});
// Start the game
initGame();
gameLoop();
</script>
</body>
</html>Reasoning trace (9,452 tokens)
This is a fun creative task! I need to make a Snake game with a train theme. Let me break it down:
1. The snake will be a train with:
- A locomotive at the front
- Colorful wagons/cars following
- Each segment should look like a train car
2. Picking up passengers:
- Instead of food, we have "passengers" waiting on platforms
- Platforms could be drawn as squares or stations
- Passengers appear on these platforms
- When the locomotive reaches a passenger, the train grows (like in snake)
3. Game mechanics:
- Classic snake game rules
- Arrow keys or WASD to control direction
- The game should auto-play initially
- Click or press a key to start playing
Let me think about the visual design:
- The locomotive could be a larger circle/rectangle at the front with some detail
- Wagons could be smaller connected rectangles in different colors
- Passengers could be small figures or simple indicators
- Platforms could be drawn as stations where passengers wait
I'll create this with canvas rendering for smooth animation.
Key features to implement:
1. Train (snake) with locomotive + colorful wagons
2. Grid-based movement (classic snake)
3. Passenger spawn points (platforms)
4. Collision detection with passengers to grow the train
5. Collision with walls and self for game over
6. Auto-play demo mode initially
7. Click/key to start playing
Let me code this:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Train Snake Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: Arial, sans-serif;
}
#gameContainer {
position: relative;
background: #1a1a2e;
border: 4px solid #16c784;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
```
I'm setting up a dark-themed container with a vibrant green border and gradient purple background to make the game visually pop.
Now I need canvas styling, a start message overlay, and a score display positioned in the top-left corner with a text shadow for readability.
For game over, I'll build a hidden overlay centered on screen with dark background, red heading text, and paragraphs showing final score plus restart instructions. The HTML structure wraps everything in a container with the canvas, score counter, start message, and game over screen as siblings.
Setting up the script, I grab references to the canvas context and all the UI elements I'll need to show or hide. I make the canvas responsive by capping its size at 800x600 but shrinking it to fit the window with some padding, calling resizeCanvas on load and whenever the window resizes. I define grid size at 30px to use as the base unit for wagon dimensions and other game measurements.
I set up state for the train as an array, current and next direction vectors, the passengers array, score, and running/game-over flags. I add an autoPlay flag and a frame counter for timing. I pick a palette of eight pastel-ish colors to cycle through for wagon rendering. Then I start a Passenger class, giving each one a random grid position and a draw method that converts grid coordinates to pixel coordinates.
ng = true;
gameOver = false;
frameCount = 0;
for (let i = 0; i < 3; i++) {
passengers.push(new Passenger());
}
updateScore();
gameOverScreen.style.display = 'none';
startMessage.classList.add('hidden');
}
Score display just needs the passenger count text. For the locomotive, I'll draw a red body, black cabin with sky-blue window, and a small smokestack to give it a classic train look.
// Wagon trim
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.strokeRect(x + 2, y + 4, GRID_SIZE - 4, GRID_SIZE - 8);
// Windows
ctx.fillStyle = '#87CEEB';
ctx.fillRect(x + 5, y + 7, 5, 5);
ctx.fillRect(x + 14, y + 7, 5, 5);
Adding matching wheels to the wagon, then drawTrain loops through segments drawing the locomotive at index 0 and wagons for the rest.
Moving into update(), with frameCount incrementing each frame and auto-play logic that finds the closest passenger using Manhattan distance, then randomly decides whether to steer the head toward it horizontally or vertically.
The actual train movement happens every 8 frames, where direction gets set to nextDirection, a new head position is calculated, and then checked against wall boundaries to call endGame() if out of bounds. Self-collision detection against existing segments follows.
After confirming no collisions, the new head gets added to the train. Passenger collision is checked by looping through the passengers array to find a matching grid position. If eaten, that passenger is removed and replaced with a new one, score increments and updateScore() runs; otherwise the tail is popped to maintain length. endGame() begins by setting gameRunning to false.
I need the game to show "Click or press a key to start" initially and run in auto-play demo mode until interrupted. Drawing the canvas involves clearing it, rendering faint grid lines, drawing passengers and the train, then looping through requestAnimationFrame. Input handling checks for arrow keys or WASD, toggling direction unless already moving that axis, and clicking or pressing a key restarts the game or breaks auto-play.
Let me restructure the full HTML now with proper styling for the game container, canvas, score display, start message, and game-over screen. I'll include a Passenger class that spawns randomly on the grid and draws a simple platform/figure, an initGame function to reset the train position based on grid dimensions, a drawLocomotive function for rendering the train head with cabin and smokestack details, and the complete game loop tying everything together with resize handling for responsiveness.