Hello World

test

123

test

123

Snake Game

(function() {
    const canvas = document.querySelector('.ephemeral-bloom');
    if (!canvas) {
        console.error('No .ephemeral-bloom element found to run snake in!');
        return;
    }
 
    const ctx = canvas.getContext('2d');
    const GRID_SIZE = 20; // Number of tiles across/down
    const TILE_SIZE = canvas.width / GRID_SIZE; // Size of each tile
 
    let snake = [];
    let food = {};
    let direction = 'right';
    let score = 0;
    let gameOver = false;
    let gameLoopInterval;
    const GAME_SPEED = 150; // milliseconds per frame (lower = faster)
 
    // Prepare font for drawing emojis
    ctx.font = `${TILE_SIZE * 0.9}px sans-serif`; // Adjust font size to fit tile
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
 
    function initGame() {
        snake = [
            { x: 8, y: 10 },
            { x: 9, y: 10 },
            { x: 10, y: 10 }
        ];
        direction = 'right';
        score = 0;
        gameOver = false;
        generateFood();
        if (gameLoopInterval) {
            clearInterval(gameLoopInterval);
        }
        gameLoopInterval = setInterval(gameLoop, GAME_SPEED);
        draw();
    }
 
    function generateFood() {
        let newFoodPos;
        let collisionWithSnake;
        do {
            newFoodPos = {
                x: Math.floor(Math.random() * GRID_SIZE),
                y: Math.floor(Math.random() * GRID_SIZE)
            };
            // Ensure food doesn't spawn on the snake
            collisionWithSnake = snake.some(segment =>
                segment.x === newFoodPos.x && segment.y === newFoodPos.y
            );
        } while (collisionWithSnake);
        food = newFoodPos;
    }
 
    function draw() {
        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
 
        // Draw score
        ctx.fillStyle = '#333';
        ctx.font = '20px sans-serif';
        ctx.fillText(`Score: ${score}`, canvas.width / 2, 25);
        ctx.font = `${TILE_SIZE * 0.9}px sans-serif`; // Reset font for game elements
 
        // Draw snake
        snake.forEach(segment => {
            ctx.fillText('🍎', segment.x * TILE_SIZE + TILE_SIZE / 2, segment.y * TILE_SIZE + TILE_SIZE / 2);
        });
 
        // Draw food
        ctx.fillText('🍎', food.x * TILE_SIZE + TILE_SIZE / 2, food.y * TILE_SIZE + TILE_SIZE / 2);
 
        // Draw Game Over message
        if (gameOver) {
            ctx.fillStyle = 'red';
            ctx.font = '40px sans-serif';
            ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2);
            ctx.font = '20px sans-serif';
            ctx.fillText('Click a direction button (or use arrow keys) to restart', canvas.width / 2, canvas.height / 2 + 40);
        }
    }
 
    function gameLoop() {
        if (gameOver) {
            clearInterval(gameLoopInterval);
            return;
        }
 
        const head = { x: snake[snake.length - 1].x, y: snake[snake.length - 1].y };
 
        // Update head position based on direction
        switch (direction) {
            case 'up': head.y--; break;
            case 'down': head.y++; break;
            case 'left': head.x--; break;
            case 'right': head.x++; break;
        }
 
        // Check for collisions
        const collidedWithWall = head.x < 0 || head.x >= GRID_SIZE || head.y < 0 || head.y >= GRID_SIZE;
        // Check for self-collision (excluding the very last segment which is the head itself)
        const collidedWithSelf = snake.some((segment, index) =>
            index < snake.length - 1 && segment.x === head.x && segment.y === head.y
        );
 
        if (collidedWithWall || collidedWithSelf) {
            gameOver = true;
            draw(); // Draw final state with "Game Over"
            clearInterval(gameLoopInterval);
            return;
        }
 
        snake.push(head); // Add new head
 
        // Check if food was eaten
        if (head.x === food.x && head.y === food.y) {
            score++;
            generateFood();
        } else {
            snake.shift(); // Remove tail if no food eaten
        }
 
        draw();
    }
 
    function changeDirection(newDir) {
        if (gameOver) {
            // If game is over, any valid direction button press restarts the game
            initGame();
            return;
        }
 
        const oppositeDirections = {
            'up': 'down',
            'down': 'up',
            'left': 'right',
            'right': 'left'
        };
 
        // Prevent immediate reversal unless the snake has only one segment (initial state)
        if (snake.length > 1 && newDir === oppositeDirections[direction]) {
            return;
        }
        direction = newDir;
    }
 
    // Event listeners for buttons
    const controlsDiv = document.querySelector('.snake-controls');
    if (controlsDiv) {
        controlsDiv.addEventListener('click', (event) => {
            const button = event.target.closest('button');
            if (button && button.dataset.direction) {
                changeDirection(button.dataset.direction);
            }
        });
    }
 
    // Optional: Keyboard controls for convenience
    document.addEventListener('keydown', (e) => {
        if (gameOver && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'w', 'a', 's', 'd'].includes(e.key.toLowerCase())) {
            initGame(); // Restart on arrow/WASD key press
            return;
        }
        switch (e.key.toLowerCase()) {
            case 'arrowup':
            case 'w':
                changeDirection('up');
                break;
            case 'arrowdown':
            case 's':
                changeDirection('down');
                break;
            case 'arrowleft':
            case 'a':
                changeDirection('left');
                break;
            case 'arrowright':
            case 'd':
                changeDirection('right');
                break;
        }
    });
 
    initGame(); // Start the game when the script runs
})();

Chat