Snake Battle: Human vs AI on Drawaria

Play a Snake Battle game (Human vs AI) on drawaria.online

// ==UserScript==
// @name         Snake Battle: Human vs AI on Drawaria
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Play a Snake Battle game (Human vs AI) on drawaria.online
// @author       YouTubeDrawaria
// @match        https://drawaria.online/*
// @grant        none
// @license      MIT
// @icon         https://drawaria.online/avatar/cache/86e33830-86ea-11ec-8553-bff27824cf71.jpg
// ==/UserScript==

(function () {
    'use strict';

    // Create game container
    const gameContainer = document.createElement('div');
    gameContainer.style.position = 'fixed';
    gameContainer.style.top = '20px';
    gameContainer.style.right = '20px';
    gameContainer.style.zIndex = '10000';
    gameContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
    gameContainer.style.padding = '10px';
    gameContainer.style.borderRadius = '10px';
    gameContainer.style.boxShadow = '0 0 20px rgba(0, 255, 255, 0.5)';

    // Add game title
    const title = document.createElement('h3');
    title.textContent = 'Snake Battle 🐍';
    title.style.color = '#00ffff';
    title.style.textAlign = 'center';
    title.style.margin = '0 0 10px 0';
    gameContainer.appendChild(title);

    // Add score display
    const score = document.createElement('div');
    score.id = 'score';
    score.textContent = '🚀 PLAYER: 0 | 🤖 AI: 0';
    score.style.color = '#ffffff';
    score.style.fontSize = '16px';
    score.style.marginBottom = '10px';


    // Add canvas for the game
    const canvas = document.createElement('canvas');
    canvas.id = 'gameBoard';
    canvas.width = 400;
    canvas.height = 300;
    canvas.style.border = '2px solid #00ffff';
    canvas.style.borderRadius = '10px';
    canvas.style.backgroundColor = '#000000';
    gameContainer.appendChild(canvas);

    // Add restart button
    const restartBtn = document.createElement('button');
    restartBtn.textContent = '🔄 NEW BATTLE';
    restartBtn.style.display = 'block';
    restartBtn.style.margin = '10px auto 0';
    restartBtn.style.padding = '8px 16px';
    restartBtn.style.backgroundColor = '#00ffff';
    restartBtn.style.color = '#000000';
    restartBtn.style.border = 'none';
    restartBtn.style.borderRadius = '20px';
    restartBtn.style.cursor = 'pointer';
    restartBtn.style.fontWeight = 'bold';
    restartBtn.onclick = resetGame;
    gameContainer.appendChild(restartBtn);

    // Append game container to the body
    document.body.appendChild(gameContainer);

    // Game logic
    const ctx = canvas.getContext('2d');
    const GRID_SIZE = 20;
    const CELL_SIZE = canvas.width / GRID_SIZE;

    let particles = [];
    let playerScore = 0;
    let aiScore = 0;
    let gameSpeed = 100;
    let gameLoop;

    let obstacles = [];
    let playerSnake = [{ x: 5, y: 5 }];
    let aiSnake = [{ x: GRID_SIZE - 5, y: GRID_SIZE - 5 }];
    let playerDirection = 'right';
    let aiDirection = 'left';
    let food = generateFood();

    function generateObstacles() {
        const obstacles = [];
        for (let i = 2; i < GRID_SIZE - 2; i += 4) {
            for (let j = 2; j < GRID_SIZE - 2; j += 4) {
                if (Math.random() > 0.5) {
                    obstacles.push({ x: i, y: j });
                    obstacles.push({ x: i + 1, y: j });
                    obstacles.push({ x: i, y: j + 1 });
                }
            }
        }
        return obstacles;
    }

    function generateFood() {
        let position;
        do {
            position = {
                x: Math.floor(Math.random() * (GRID_SIZE - 4)) + 2,
                y: Math.floor(Math.random() * (GRID_SIZE - 4)) + 2
            };
        } while ([...playerSnake, ...aiSnake, ...obstacles].some(item =>
            item.x === position.x && item.y === position.y));
        return position;
    }

    function aiPathfinding() {
        const head = aiSnake[0];
        const queue = [{ pos: head, path: [] }];
        const visited = new Set();

        while (queue.length > 0) {
            const current = queue.shift();
            if (current.pos.x === food.x && current.pos.y === food.y) {
                return current.path[0] || aiDirection;
            }

            const directions = [
                { dir: 'up', x: 0, y: -1 },
                { dir: 'down', x: 0, y: 1 },
                { dir: 'left', x: -1, y: 0 },
                { dir: 'right', x: 1, y: 0 }
            ];

            for (const d of directions) {
                const newPos = {
                    x: current.pos.x + d.x,
                    y: current.pos.y + d.y
                };
                const posKey = `${newPos.x},${newPos.y}`;

                if (!visited.has(posKey) &&
                    newPos.x >= 0 && newPos.x < GRID_SIZE &&
                    newPos.y >= 0 && newPos.y < GRID_SIZE &&
                    !obstacles.some(o => o.x === newPos.x && o.y === newPos.y) &&
                    !aiSnake.some(s => s.x === newPos.x && s.y === newPos.y)) {
                    visited.add(posKey);
                    queue.push({
                        pos: newPos,
                        path: [...current.path, d.dir]
                    });
                }
            }
        }
        return aiDirection;
    }

    function updateParticles() {
        particles = particles.filter(p => {
            p.x += p.velocity.x;
            p.y += p.velocity.y;
            p.life -= 0.02;
            return p.life > 0;
        });
    }

    function draw() {
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.strokeStyle = 'rgba(0, 255, 255, 0.05)';
        for (let i = 0; i < GRID_SIZE; i++) {
            ctx.beginPath();
            ctx.moveTo(i * CELL_SIZE, 0);
            ctx.lineTo(i * CELL_SIZE, canvas.height);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(0, i * CELL_SIZE);
            ctx.lineTo(canvas.width, i * CELL_SIZE);
            ctx.stroke();
        }

        ctx.fillStyle = '#2a2a2a';
        obstacles.forEach(obs => {
            ctx.beginPath();
            ctx.roundRect(obs.x * CELL_SIZE, obs.y * CELL_SIZE, CELL_SIZE, CELL_SIZE, 5);
            ctx.fill();
        });

        ctx.fillStyle = '#ff006e';
        ctx.shadowColor = '#ff006e';
        ctx.shadowBlur = 20;
        ctx.beginPath();
        ctx.arc(
            (food.x + 0.5) * CELL_SIZE,
            (food.y + 0.5) * CELL_SIZE,
            CELL_SIZE / 2 - 2,
            0,
            Math.PI * 2
        );
        ctx.fill();
        ctx.shadowBlur = 0;

        playerSnake.forEach((segment, index) => {
            const gradient = ctx.createLinearGradient(
                segment.x * CELL_SIZE,
                segment.y * CELL_SIZE,
                (segment.x + 1) * CELL_SIZE,
                (segment.y + 1) * CELL_SIZE
            );
            gradient.addColorStop(0, '#00ff88');
            gradient.addColorStop(1, '#00ff00');
            ctx.fillStyle = gradient;
            ctx.beginPath();
            ctx.roundRect(
                segment.x * CELL_SIZE + 2,
                segment.y * CELL_SIZE + 2,
                CELL_SIZE - 4,
                CELL_SIZE - 4,
                8
            );
            ctx.fill();
        });

        aiSnake.forEach((segment, index) => {
            const gradient = ctx.createLinearGradient(
                segment.x * CELL_SIZE,
                segment.y * CELL_SIZE,
                (segment.x + 1) * CELL_SIZE,
                (segment.y + 1) * CELL_SIZE
            );
            gradient.addColorStop(0, '#ff6600');
            gradient.addColorStop(1, '#ff0000');
            ctx.fillStyle = gradient;
            ctx.beginPath();
            ctx.roundRect(
                segment.x * CELL_SIZE + 2,
                segment.y * CELL_SIZE + 2,
                CELL_SIZE - 4,
                CELL_SIZE - 4,
                8
            );
            ctx.fill();
        });

        particles.forEach(p => {
            ctx.fillStyle = p.color;
            ctx.globalAlpha = p.life;
            ctx.beginPath();
            ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
            ctx.fill();
        });
        ctx.globalAlpha = 1;
    }

    function gameOver() {
        clearInterval(gameLoop);
        setTimeout(() => {
            alert(`GAME OVER\nPlayer: ${playerScore}\nAI: ${aiScore}`);
            resetGame();
        }, 1000);
    }

    function resetGame() {
        playerSnake = [{ x: 5, y: 5 }];
        aiSnake = [{ x: GRID_SIZE - 5, y: GRID_SIZE - 5 }];
        playerDirection = 'right';
        aiDirection = 'left';
        playerScore = aiScore = 0;
        food = generateFood();
        obstacles = generateObstacles();
        particles = [];
        score.textContent = '🚀 PLAYER: 0 | 🤖 AI: 0';
        if (gameLoop) clearInterval(gameLoop);
        gameLoop = setInterval(update, gameSpeed);
    }

    document.addEventListener('keydown', (e) => {
        switch (e.key) {
            case 'ArrowUp': if (playerDirection !== 'down') playerDirection = 'up'; break;
            case 'ArrowDown': if (playerDirection !== 'up') playerDirection = 'down'; break;
            case 'ArrowLeft': if (playerDirection !== 'right') playerDirection = 'left'; break;
            case 'ArrowRight': if (playerDirection !== 'left') playerDirection = 'right'; break;
        }
    });

    function update() {
        aiDirection = aiPathfinding();

        const playerHead = { ...playerSnake[0] };
        const aiHead = { ...aiSnake[0] };

        switch (playerDirection) {
            case 'up': playerHead.y--; break;
            case 'down': playerHead.y++; break;
            case 'left': playerHead.x--; break;
            case 'right': playerHead.x++; break;
        }

        switch (aiDirection) {
            case 'up': aiHead.y--; break;
            case 'down': aiHead.y++; break;
            case 'left': aiHead.x--; break;
            case 'right': aiHead.x++; break;
        }

        const playerCollision = checkCollision(playerHead, playerSnake);
        const aiCollision = checkCollision(aiHead, aiSnake);

        if (playerCollision || aiCollision) {
            gameOver();
            return;
        }

        playerSnake.unshift(playerHead);
        aiSnake.unshift(aiHead);

        if (playerHead.x === food.x && playerHead.y === food.y) {
            playerScore++;
            food = generateFood();
        } else {
            playerSnake.pop();
        }

        if (aiHead.x === food.x && aiHead.y === food.y) {
            aiScore++;
            food = generateFood();
        } else {
            aiSnake.pop();
        }

        score.textContent = `🚀 PLAYER: ${playerScore} | 🤖 AI: ${aiScore}`;
        updateParticles();
        draw();
    }

    function checkCollision(head, snake) {
        return head.x < 0 || head.x >= GRID_SIZE ||
            head.y < 0 || head.y >= GRID_SIZE ||
            obstacles.some(o => o.x === head.x && o.y === head.y) ||
            snake.slice(1).some(s => s.x === head.x && s.y === head.y) ||
            (snake === playerSnake ? aiSnake : playerSnake).some(s =>
                s.x === head.x && s.y === head.y);
    }

    resetGame();
})();