AI Code Test

Angry Birds

Review the original prompt, inspect the generated code, and compare how different AI models handled the same coding task.

Back to All Tests

Angry Birds

Gemini Flash 3.5 (Standard)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Angry Birds Clone</title>
    <!-- Include Matter.js for physics -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            user-select: none;
        }
        body {
            margin: 0;
            padding: 0;
            background: #111;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            overflow: hidden;
        }
        #game-container {
            position: relative;
            width: 1000px;
            height: 600px;
            background: #70c5ce; /* Sky blue default */
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            border-radius: 8px;
            overflow: hidden;
        }
        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }
        .screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: rgba(0, 0, 0, 0.45);
            backdrop-filter: blur(4px);
            color: white;
            z-index: 10;
            transition: opacity 0.3s ease;
        }
        .hidden {
            opacity: 0;
            pointer-events: none;
            display: none !important;
        }
        h1 {
            font-size: 4rem;
            margin-bottom: 2rem;
            text-shadow: 3px 3px 0px #bd3b1b, 6px 6px 0px #000;
            color: #f1c40f;
            letter-spacing: 2px;
        }
        .btn {
            background: #e67e22;
            color: white;
            border: none;
            padding: 15px 40px;
            font-size: 1.5rem;
            font-weight: bold;
            border-radius: 50px;
            cursor: pointer;
            box-shadow: 0 5px 0 #d35400, 0 10px 20px rgba(0,0,0,0.3);
            transition: transform 0.1s, box-shadow 0.1s;
        }
        .btn:hover {
            background: #f39c12;
        }
        .btn:active {
            transform: translateY(4px);
            box-shadow: 0 1px 0 #d35400, 0 5px 10px rgba(0,0,0,0.3);
        }
        /* Level Selector Grid */
        .grid {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 20px;
            max-width: 600px;
            padding: 20px;
        }
        .level-btn {
            background: #3498db;
            color: white;
            border: none;
            width: 70px;
            height: 70px;
            font-size: 1.5rem;
            font-weight: bold;
            border-radius: 12px;
            cursor: pointer;
            box-shadow: 0 4px 0 #2980b9;
            display: flex;
            justify-content: center;
            align-items: center;
            transition: background 0.2s;
        }
        .level-btn:hover {
            background: #2980b9;
        }
        .level-btn.locked {
            background: #7f8c8d;
            box-shadow: 0 4px 0 #95a5a6;
            cursor: not-allowed;
            opacity: 0.6;
        }
        /* In-Game HUD overlay */
        #hud {
            position: absolute;
            top: 15px;
            left: 15px;
            right: 15px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: white;
            font-size: 1.25rem;
            font-weight: bold;
            text-shadow: 1px 1px 3px rgba(0,0,0,0.8);
            pointer-events: none;
            z-index: 5;
        }
        .hud-btn {
            background: #e74c3c;
            padding: 8px 15px;
            font-size: 1rem;
            border-radius: 6px;
            box-shadow: 0 3px 0 #c0392b;
            pointer-events: auto;
        }
        #game-over-title {
            font-size: 3rem;
            margin-bottom: 1rem;
        }
        .score-display {
            font-size: 1.5rem;
            margin-bottom: 2rem;
            color: #f1c40f;
        }
        .btn-row {
            display: flex;
            gap: 15px;
        }
    </style>
</head>
<body>

<div id="game-container">
    <!-- HUD Layer -->
    <div id="hud" class="hidden">
        <div>Level: <span id="hud-level">1</span></div>
        <div>Birds Left: <span id="hud-birds">3</span></div>
        <button class="btn hud-btn" id="btn-restart-hud">Restart</button>
    </div>

    <!-- Main Menu Screen -->
    <div id="menu-screen" class="screen">
        <h1>ANGRY SLINGS</h1>
        <button class="btn" id="btn-play">PLAY</button>
    </div>

    <!-- Level Select Screen -->
    <div id="level-screen" class="screen hidden">
        <h1>SELECT LEVEL</h1>
        <div class="grid" id="level-grid"></div>
        <button class="btn" id="btn-level-back" style="margin-top:20px; font-size:1rem; padding: 10px 25px;">Back</button>
    </div>

    <!-- Game Over / Victory Screen -->
    <div id="game-over-screen" class="screen hidden">
        <h1 id="game-over-title">VICTORY!</h1>
        <div class="score-display" id="game-over-msg">All targets smashed!</div>
        <div class="btn-row">
            <button class="btn" id="btn-go-menu" style="font-size:1.1rem; padding:12px 25px; background:#7f8c8d; box-shadow:0 4px 0 #95a5a6;">Menu</button>
            <button class="btn" id="btn-go-restart" style="font-size:1.1rem; padding:12px 25px; background:#3498db; box-shadow:0 4px 0 #2980b9;">Retry</button>
            <button class="btn" id="btn-go-next" style="font-size:1.1rem; padding:12px 25px;">Next Level</button>
        </div>
    </div>

    <!-- Physics Render Canvas -->
    <canvas id="gameCanvas"></canvas>
</div>

<script>
// --- Core Game Configuration & State ---
const { Engine, Render, Runner, World, Bodies, Body, Constraint, Mouse, MouseConstraint, Events, Composite } = Matter;

let engine, render, runner;
let currentLevel = 1;
let unlockedLevel = 1;
let gameState = 'menu'; // menu, levels, playing, gameover

let bird, slingshot;
let remainingBirds = 3;
let targets = [];
let blocks = [];
let ground, backdrop;

let isBirdFlying = false;
let canvas = document.getElementById('gameCanvas');
const viewWidth = 1000;
const viewHeight = 600;

// Save/Load progress from localStorage
if(localStorage.getItem('angry_unlocked_level')) {
    unlockedLevel = parseInt(localStorage.getItem('angry_unlocked_level'));
}

// --- DOM References ---
const menuScreen = document.getElementById('menu-screen');
const levelScreen = document.getElementById('level-screen');
const gameOverScreen = document.getElementById('game-over-screen');
const hud = document.getElementById('hud');

// --- Level Design Data (10 Levels) ---
// Defines block placements [x, y, width, height, option_overrides] and targets [x, y, radius]
const levelDefinitions = {
    1: {
        birds: 3,
        targets: [{x: 800, y: 520, r: 20}],
        blocks: [
            {x: 800, y: 550, w: 100, h: 20}
        ]
    },
    2: {
        birds: 3,
        targets: [{x: 800, y: 480, r: 20}],
        blocks: [
            {x: 760, y: 520, w: 20, h: 100},
            {x: 840, y: 520, w: 20, h: 100},
            {x: 800, y: 460, w: 120, h: 20}
        ]
    },
    3: {
        birds: 3,
        targets: [{x: 750, y: 520, r: 18}, {x: 850, y: 525, r: 18}],
        blocks: [
            {x: 750, y: 550, w: 80, h: 20},
            {x: 850, y: 550, w: 80, h: 20},
            {x: 800, y: 480, w: 20, h: 120}
        ]
    },
    4: {
        birds: 3,
        targets: [{x: 800, y: 400, r: 18}],
        blocks: [
            {x: 760, y: 520, w: 20, h: 100},
            {x: 840, y: 520, w: 20, h: 100},
            {x: 800, y: 460, w: 100, h: 20},
            {x: 780, y: 420, w: 20, h: 60},
            {x: 820, y: 420, w: 20, h: 60},
            {x: 800, y: 380, w: 80, h: 20}
        ]
    },
    5: {
        birds: 3,
        targets: [{x: 720, y: 525, r: 20}, {x: 880, y: 525, r: 20}, {x: 800, y: 400, r: 15}],
        blocks: [
            {x: 720, y: 550, w: 60, h: 20},
            {x: 880, y: 550, w: 60, h: 20},
            {x: 800, y: 500, w: 30, h: 160},
            {x: 800, y: 410, w: 100, h: 20}
        ]
    },
    6: {
        birds: 4,
        targets: [{x: 770, y: 520, r: 18}, {x: 830, y: 520, r: 18}, {x: 800, y: 420, r: 18}],
        blocks: [
            {x: 740, y: 510, w: 20, h: 140},
            {x: 860, y: 510, w: 20, h: 140},
            {x: 800, y: 430, w: 140, h: 20},
            {x: 770, y: 380, w: 20, h: 80},
            {x: 830, y: 380, w: 20, h: 80},
            {x: 800, y: 330, w: 100, h: 20}
        ]
    },
    7: {
        birds: 3,
        targets: [{x: 800, y: 340, r: 22}],
        blocks: [
            // High Pyramid Structure
            {x: 750, y: 530, w: 30, h: 100},
            {x: 850, y: 530, w: 30, h: 100},
            {x: 800, y: 470, w: 160, h: 20},
            {x: 770, y: 410, w: 25, h: 100},
            {x: 830, y: 410, w: 25, h: 100},
            {x: 800, y: 350, w: 110, h: 20}
        ]
    },
    8: {
        birds: 4,
        targets: [{x: 650, y: 525, r: 18}, {x: 800, y: 525, r: 18}, {x: 950, y: 525, r: 18}],
        blocks: [
            {x: 720, y: 500, w: 20, h: 150},
            {x: 880, y: 500, w: 20, h: 150},
            {x: 800, y: 415, w: 150, h: 20}
        ]
    },
    9: {
        birds: 4,
        targets: [{x: 800, y: 525, r: 16}, {x: 800, y: 445, r: 16}, {x: 800, y: 365, r: 16}],
        blocks: [
            {x: 750, y: 530, w: 20, h: 100}, {x: 850, y: 530, w: 20, h: 100},
            {x: 800, y: 475, w: 120, h: 15},
            {x: 760, y: 430, w: 20, h: 80},  {x: 840, y: 430, w: 20, h: 80},
            {x: 800, y: 385, w: 100, h: 15}
        ]
    },
    10: {
        birds: 4,
        targets: [{x: 720, y: 430, r: 18}, {x: 880, y: 430, r: 18}, {x: 800, y: 270, r: 20}],
        blocks: [
            // Stronghold setup
            {x: 720, y: 510, w: 30, h: 140}, {x: 880, y: 510, w: 30, h: 140},
            {x: 800, y: 430, w: 210, h: 20},
            {x: 750, y: 360, w: 25, h: 120}, {x: 850, y: 360, w: 25, h: 120},
            {x: 800, y: 290, w: 140, h: 20}
        ]
    }
};

// --- Initialization Engine Setup ---
function initPhysics() {
    engine = Engine.create();
    // Increase velocity iterations for structural stability
    engine.positionIterations = 8;
    engine.velocityIterations = 8;

    render = Render.create({
        canvas: canvas,
        engine: engine,
        options: {
            width: viewWidth,
            height: viewHeight,
            wireframes: false,
            background: '#70c5ce'
        }
    });

    Render.run(render);
    runner = Runner.create();
    Runner.run(runner, engine);

    // Constant solid static boundaries
    ground = Bodies.rectangle(viewWidth / 2, 590, viewWidth * 2, 40, { 
        isStatic: true, 
        render: { fillStyle: '#27ae60' } 
    });
    World.add(engine.world, ground);

    // Setup mouse integration for pulling the slingshot
    const mouse = Mouse.create(render.canvas);
    const mouseConstraint = MouseConstraint.create(engine, {
        mouse: mouse,
        constraint: {
            stiffness: 0.1,
            render: { visible: false }
        }
    });
    World.add(engine.world, mouseConstraint);
    render.mouse = mouse;

    // Monitor engine loops to release slingshot cleanly
    Events.on(engine, 'afterUpdate', handleSlingshotRelease);
}

// --- Screen Router ---
function showScreen(screen) {
    menuScreen.classList.add('hidden');
    levelScreen.classList.add('hidden');
    gameOverScreen.classList.add('hidden');
    hud.classList.add('hidden');

    if (screen === 'menu') menuScreen.classList.remove('hidden');
    if (screen === 'levels') {
        renderLevelGrid();
        levelScreen.classList.remove('hidden');
    }
    if (screen === 'playing') hud.classList.remove('hidden');
    if (screen === 'gameover') gameOverScreen.classList.remove('hidden');
}

function renderLevelGrid() {
    const grid = document.getElementById('level-grid');
    grid.innerHTML = '';
    for (let i = 1; i <= 10; i++) {
        const btn = document.createElement('button');
        btn.className = `level-btn ${i > unlockedLevel ? 'locked' : ''}`;
        btn.innerText = i;
        btn.onclick = () => {
            if (i <= unlockedLevel) {
                currentLevel = i;
                loadLevel(i);
            }
        };
        grid.appendChild(btn);
    }
}

// --- Level Building Logic ---
function loadLevel(levelNum) {
    gameState = 'playing';
    showScreen('playing');

    // Clean out previous round bodies safely
    if (bird) World.remove(engine.world, bird);
    if (slingshot) World.remove(engine.world, slingshot);
    targets.forEach(t => World.remove(engine.world, t));
    blocks.forEach(b => World.remove(engine.world, b));

    targets = [];
    blocks = [];
    isBirdFlying = false;

    const data = levelDefinitions[levelNum];
    remainingBirds = data.birds;

    document.getElementById('hud-level').innerText = levelNum;
    document.getElementById('hud-birds').innerText = remainingBirds;

    // Build functional destructible buildings
    data.blocks.forEach(bConfig => {
        let b = Bodies.rectangle(bConfig.x, bConfig.y, bConfig.w, bConfig.h, {
            density: 0.0008,
            friction: 0.4,
            render: { fillStyle: '#b37841', strokeStyle: '#784e24', lineWidth: 2 }
        });
        blocks.push(b);
        World.add(engine.world, b);
    });

    // Spawn high value targets
    data.targets.forEach(tConfig => {
        let t = Bodies.circle(tConfig.x, tConfig.y, tConfig.r, {
            density: 0.0004,
            friction: 0.2,
            label: 'target',
            render: { fillStyle: '#badc58', strokeStyle: '#6ab04c', lineWidth: 3 }
        });
        targets.push(t);
        World.add(engine.world, t);
    });

    spawnBird();
}

function spawnBird() {
    if (bird) World.remove(engine.world, bird);
    if (slingshot) World.remove(engine.world, slingshot);

    const anchorX = 200;
    const anchorY = 420;

    bird = Bodies.circle(anchorX, anchorY, 16, {
        density: 0.003,
        frictionAir: 0.005,
        render: { fillStyle: '#e74c3c' }
    });

    slingshot = Constraint.create({
        pointA: { x: anchorX, y: anchorY },
        bodyB: bird,
        stiffness: 0.08,
        damping: 0.01,
        render: { strokeStyle: '#4a3728', lineWidth: 5 }
    });

    World.add(engine.world, [bird, slingshot]);
    isBirdFlying = false;
    document.getElementById('hud-birds').innerText = remainingBirds;
}

// --- Slingshot Logic Core ---
function handleSlingshotRelease() {
    if (gameState !== 'playing' || !bird || !slingshot) return;

    // Detect user release after pulling past resting anchor point
    if (render.mouse.button === -1 && isBirdFlying === false) {
        // If bird is pulled back and released
        if (bird.position.x > 215 || bird.position.x < 185 || bird.position.y > 435 || bird.position.y < 405) {
            if (bird.position.x < 220) { // Forward threshold break
                isBirdFlying = true;
                remainingBirds--;
                
                // Detach constraint after a slight programmatic delay to let physics project forward acceleration
                setTimeout(() => {
                    if (slingshot) {
                        slingshot.bodyB = null;
                        slingshot.render.visible = false;
                    }
                }, 40);

                // Start evaluating evaluation window for next actions
                setTimeout(evaluateTurnResolution, 4000);
            }
        }
    }
}

// --- Win / Loss Evaluators ---
function evaluateTurnResolution() {
    if (gameState !== 'playing') return;

    // Clear falling/out-of-bounds targets
    targets = targets.filter(t => {
        if (t.position.y > 580 || t.position.x > viewWidth + 100) {
            World.remove(engine.world, t);
            return false;
        }
        return true;
    });

    // Check Win condition
    if (targets.length === 0) {
        triggerEndscreen(true);
        return;
    }

    // Check Loss condition or Spawn Next Bird
    if (remainingBirds > 0) {
        spawnBird();
    } else {
        // Give structures extra 2 seconds to settle before declaring failure
        setTimeout(() => {
            targets = targets.filter(t => t.position.y < 580);
            if (targets.length > 0) {
                triggerEndscreen(false);
            } else {
                triggerEndscreen(true);
            }
        }, 2000);
    }
}

function triggerEndscreen(isVictory) {
    gameState = 'gameover';
    showScreen('gameover');

    const title = document.getElementById('game-over-title');
    const msg = document.getElementById('game-over-msg');
    const nextBtn = document.getElementById('btn-go-next');

    if (isVictory) {
        title.innerText = "VICTORY!";
        title.style.color = "#f1c40f";
        msg.innerText = `You smashed Level ${currentLevel}!`;
        nextBtn.classList.remove('hidden');

        // Advance progression
        if (currentLevel === unlockedLevel && unlockedLevel < 10) {
            unlockedLevel++;
            localStorage.setItem('angry_unlocked_level', unlockedLevel);
        }
    } else {
        title.innerText = "LEVEL FAILED";
        title.style.color = "#e74c3c";
        msg.innerText = "Targets survived. Try adjusting your angles!";
        nextBtn.classList.add('hidden');
    }
}

// --- Wire Event Handlers ---
document.getElementById('btn-play').onclick = () => showScreen('levels');
document.getElementById('btn-level-back').onclick = () => showScreen('menu');
document.getElementById('btn-restart-hud').onclick = () => loadLevel(currentLevel);

document.getElementById('btn-go-menu').onclick = () => showScreen('levels');
document.getElementById('btn-go-restart').onclick = () => loadLevel(currentLevel);
document.getElementById('btn-go-next').onclick = () => {
    if (currentLevel < 10) {
        currentLevel++;
        loadLevel(currentLevel);
    } else {
        showScreen('menu');
    }
};

// Initialize system on window mount
window.onload = () => {
    initPhysics();
    showScreen('menu');
};
</script>
</body>
</html>

Models

71
Compare code outputs