Cuando los píxeles eran épicos y las líneas te mataban (Un juego para nostalgicos del MSDOS)

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Juego Estilo Xonix Avanzado</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        body {
            font-family: 'Inter', sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            margin: 0;
            background-color: #1a202c; 
            color: #e2e8f0; 
            overflow: hidden; 
        }
        #game-container {
            background-color: #2d3748; 
            padding: 1rem;
            border-radius: 0.5rem;
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
            position: relative; /* Para superposiciones */
        }
        canvas {
            display: block;
            background-color: #4a5568; 
            border-radius: 0.375rem;
        }
        #game-info {
            display: flex;
            justify-content: space-around;
            width: 100%;
            max-width: 600px; 
            padding: 0.75rem 0;
            font-size: 1rem;
            font-weight: 600;
            color: #a0aec0; 
        }
        /* Estilos para las superposiciones (mensajes y selección de modo) */
        .overlay {
            position: absolute; 
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.85); 
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 100;
            color: white;
            text-align: center;
            padding: 1rem;
            box-sizing: border-box;
            border-radius: 0.5rem; 
        }
        .overlay h2 {
            font-size: 2rem;
            margin-bottom: 1rem; 
            color: #63b3ed; 
        }
        .overlay p {
            font-size: 1.125rem;
            margin-bottom: 1.5rem;
        }
        .overlay button, .mode-button { 
            background-color: #4299e1; 
            color: white;
            font-weight: bold;
            padding: 0.75rem 1.5rem;
            border: none;
            border-radius: 0.375rem;
            cursor: pointer;
            transition: background-color 0.2s ease-in-out;
            margin-top: 0.5rem; 
        }
        .overlay button:hover, .mode-button:hover {
            background-color: #3182ce; 
        }
        #mode-selection-overlay .mode-options {
            display: flex;
            flex-direction: column; 
            gap: 1rem; 
        }
        .mode-button {
            min-width: 200px; 
        }
        .hidden {
            display: none !important;
        }
    </style>
</head>
<body>
    <div id="game-container">
        <div id="game-info">
            <span>Modo: <span id="mode-display">-</span></span> |
            <span>Nivel: <span id="level-display">1</span></span> |
            <span>Vidas: <span id="lives-display">5</span></span> |
            <span>Área: <span id="area-display">0</span>%</span>
        </div>
        <canvas id="gameCanvas"></canvas>

        <div id="mode-selection-overlay" class="overlay"> <h2>Elige un modo de juego:</h2>
            <div class="mode-options">
                <button id="mode-xonix-button" class="mode-button">Modo Área (Xonix)</button>
                <button id="mode-isolate-button" class="mode-button">Modo Aislar Bolas</button>
            </div>
        </div>

        <div id="message-overlay" class="overlay hidden">
            <h2 id="message-title"></h2>
            <p id="message-text"></p>
            <button id="message-button">Continuar</button>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const modeDisplay = document.getElementById('mode-display');
        const levelDisplay = document.getElementById('level-display');
        const livesDisplay = document.getElementById('lives-display');
        const areaDisplay = document.getElementById('area-display');

        const messageOverlay = document.getElementById('message-overlay');
        const messageTitle = document.getElementById('message-title');
        const messageText = document.getElementById('message-text');
        let messageButton = document.getElementById('message-button'); 

        const modeSelectionOverlay = document.getElementById('mode-selection-overlay');
        const modeXonixButton = document.getElementById('mode-xonix-button');
        const modeIsolateButton = document.getElementById('mode-isolate-button');

        const CANVAS_WIDTH = 600;
        const CANVAS_HEIGHT = 400;
        canvas.width = CANVAS_WIDTH;
        canvas.height = CANVAS_HEIGHT;

        const PLAYER_SIZE = 10; 
        const PLAYER_SPEED = 10; 
        const LINE_DRAW_SPEED = 5; 
        const BALL_RADIUS = 8;
        const TARGET_AREA_PERCENTAGE = 75; 
        const INITIAL_LIVES = 5; 
        const MAX_LEVELS = 10; 
        const INITIAL_BALLS_XONIX = 2;
        const INITIAL_BALLS_ISOLATE = 3; 
                                     
        let gameMode = 'xonix'; 
        let gameState; 
        let currentLevel;
        let lives;
        let balls = []; 
        let player;     
        let activeArea = { x: 0, y: 0, width: CANVAS_WIDTH, height: CANVAS_HEIGHT }; 
        let filledAreas = []; 
        let walls = []; 
        let totalCanvasArea = CANVAS_WIDTH * CANVAS_HEIGHT;
        let conqueredAreaPercentage;

        const BALL_COLORS = ['#F56565', '#ED8936', '#ECC94B', '#48BB78', '#38B2AC', '#4299E1', '#9F7AEA', '#ED64A6'];
        const FILLED_AREA_COLOR = '#2c5282'; 
        const ACTIVE_AREA_COLOR = '#4A5568'; 
        const PLAYER_COLOR = '#A0AEC0'; 
        const LINE_COLOR = '#F7FAFC'; 
        const WALL_COLOR = '#CBD5E0'; 

        class Ball {
            constructor(x, y, dx, dy, radius, color) {
                this.x = x;
                this.y = y;
                this.dx = dx;
                this.dy = dy;
                this.radius = radius;
                this.color = color;
                this.cell = null; 
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
                ctx.closePath();
            }

            update() {
                this.x += this.dx;
                this.y += this.dy;

                let currentBoundaries = activeArea; 
                if (gameMode === 'isolate') { 
                    currentBoundaries = { x: 0, y: 0, width: CANVAS_WIDTH, height: CANVAS_HEIGHT };
                }


                if (this.x + this.radius > currentBoundaries.x + currentBoundaries.width || this.x - this.radius < currentBoundaries.x) {
                    this.dx *= -1;
                    if (this.x + this.radius > currentBoundaries.x + currentBoundaries.width) this.x = currentBoundaries.x + currentBoundaries.width - this.radius;
                    if (this.x - this.radius < currentBoundaries.x) this.x = currentBoundaries.x + this.radius;
                }
                if (this.y + this.radius > currentBoundaries.y + currentBoundaries.height || this.y - this.radius < currentBoundaries.y) {
                    this.dy *= -1;
                    if (this.y + this.radius > currentBoundaries.y + currentBoundaries.height) this.y = currentBoundaries.y + currentBoundaries.height - this.radius;
                    if (this.y - this.radius < currentBoundaries.y) this.y = currentBoundaries.y + this.radius;
                }

                if (gameMode === 'isolate' && walls) {
                    for (let wall of walls) {
                        if (wall.orientation === 'vertical') { 
                            const wallMinY = Math.min(wall.y1, wall.y2);
                            const wallMaxY = Math.max(wall.y1, wall.y2);
                            if (this.x + this.radius > wall.x1 - 1 && this.x - this.radius < wall.x1 + 1 && 
                                this.y + this.radius > wallMinY && this.y - this.radius < wallMaxY) { 
                                if ((this.dx > 0 && this.x < wall.x1) || (this.dx < 0 && this.x > wall.x1)) {
                                     this.dx *= -1;
                                     this.x = (this.x < wall.x1) ? wall.x1 - this.radius - 0.1 : wall.x1 + this.radius + 0.1;
                                }
                            }
                        } else { 
                            const wallMinX = Math.min(wall.x1, wall.x2);
                            const wallMaxX = Math.max(wall.x1, wall.x2);
                            if (this.y + this.radius > wall.y1 - 1 && this.y - this.radius < wall.y1 + 1 && 
                                this.x + this.radius > wallMinX && this.x - this.radius < wallMaxX) { 
                                 if ((this.dy > 0 && this.y < wall.y1) || (this.dy < 0 && this.y > wall.y1)) {
                                    this.dy *= -1;
                                    this.y = (this.y < wall.y1) ? wall.y1 - this.radius - 0.1 : wall.y1 + this.radius + 0.1;
                                 }
                            }
                        }
                    }
                }
            }
        }

        function initPlayer() {
            player = {
                x: CANVAS_WIDTH / 2 - PLAYER_SIZE / 2,
                y: 0, 
                edge: 'top', 
                drawingLine: null
            };
        }
        
        function initLevel(level) { 
            currentLevel = level; 
            lives = INITIAL_LIVES; 
            
            activeArea = { x: 0, y: 0, width: CANVAS_WIDTH, height: CANVAS_HEIGHT }; 
            filledAreas = []; 
            walls = []; 
            balls = []; 
            conqueredAreaPercentage = 0;
            
            initPlayer(); 
            
            let numBalls;
            let baseSpeed;
            const addedBalls = Math.floor((currentLevel - 1) / 2); 

            if (gameMode === 'xonix') {
                numBalls = INITIAL_BALLS_XONIX + addedBalls;
                baseSpeed = 1 + currentLevel * 0.25; 
            } else { 
                numBalls = INITIAL_BALLS_ISOLATE + addedBalls;
                baseSpeed = 1.25 + currentLevel * 0.2; 
            }
            
            numBalls = Math.max(gameMode === 'xonix' ? INITIAL_BALLS_XONIX : INITIAL_BALLS_ISOLATE, numBalls);
            
            for (let i = 0; i < numBalls; i++) {
                let ballX, ballY;
                let safe = false;
                let attempts = 0;
                do { 
                    ballX = BALL_RADIUS + Math.random() * (CANVAS_WIDTH - 2 * BALL_RADIUS);
                    ballY = BALL_RADIUS + Math.random() * (CANVAS_HEIGHT - 2 * BALL_RADIUS);
                    
                    let playerInitialEdge = player ? player.edge : 'top';
                    let playerInitialY = player ? player.y : 0;

                    let playerEffectiveY = (playerInitialEdge === 'top') ? playerInitialY + PLAYER_SIZE : CANVAS_HEIGHT; 
                    if (ballY > playerEffectiveY + 20) { 
                        safe = true;
                    }
                    attempts++;
                } while (!safe && attempts < 100);

                const angle = Math.random() * Math.PI * 2;
                balls.push(new Ball(
                    ballX, ballY,
                    Math.cos(angle) * baseSpeed,
                    Math.sin(angle) * baseSpeed,
                    BALL_RADIUS,
                    BALL_COLORS[i % BALL_COLORS.length]
                ));
            }
            updateUI();
            setGameState('READY');
        }

        function showModeSelectionScreen() {
            modeSelectionOverlay.classList.remove('hidden');
            messageOverlay.classList.add('hidden'); 
            modeDisplay.textContent = '-';
            levelDisplay.textContent = '1';
            livesDisplay.textContent = String(INITIAL_LIVES);
            areaDisplay.textContent = '0%';
            gameState = 'MODE_SELECT'; 
            draw(); 
        }
        
        function startGame() { 
            initLevel(1); 
        }
        
        function setGameState(newState) {
            gameState = newState;
            if (messageOverlay) { 
                messageOverlay.classList.add('hidden');
            }
             if(modeSelectionOverlay && newState !== 'MODE_SELECT'){ 
                modeSelectionOverlay.classList.add('hidden');
            }

            const numCurrentBalls = balls ? balls.length : (gameMode === 'xonix' ? INITIAL_BALLS_XONIX : INITIAL_BALLS_ISOLATE);

            let readyMessage = gameMode === 'xonix' ? 
                `Nivel ${currentLevel}. Conquista el ${TARGET_AREA_PERCENTAGE}% del área. Bolas: ${numCurrentBalls}.` : 
                `Modo Aislar - Nivel ${currentLevel}. ¡Encierra ${numCurrentBalls} bolas en celdas separadas!`;

            if (gameState === 'READY') {
                showMessage(gameMode === 'xonix' ? `Nivel ${currentLevel}` : `Aislar Bolas - Nivel ${currentLevel}`, `${readyMessage} Presiona ESPACIO para empezar.`, "Empezar", () => setGameState('PLAYING'));
            } else if (gameState === 'GAME_OVER') {
                showMessage("¡Juego Terminado!", `Te quedaste sin vidas. Nivel alcanzado: ${currentLevel}. Presiona para elegir modo.`, "Elegir Modo", () => {
                    showModeSelectionScreen(); 
                });
            } else if (gameState === 'GAME_WON') { 
                let winMsg = "";
                let nextAction = null;
                let buttonText = "Elegir Modo"; 

                if (gameMode === 'xonix') {
                     winMsg = `¡Nivel ${currentLevel} de Xonix Completado!`;
                     if (currentLevel >= MAX_LEVELS) {
                         winMsg = "¡Completaste todos los niveles de Xonix!";
                         nextAction = () => showModeSelectionScreen();
                     } else { 
                         buttonText = "Siguiente Nivel (Xonix)";
                         nextAction = () => initLevel(currentLevel + 1);
                     }
                } else { 
                    winMsg = `¡Nivel ${currentLevel} de Aislar Bolas Completado!`;
                    if (currentLevel >= MAX_LEVELS) { 
                        winMsg = "¡Completaste todos los niveles de Aislar Bolas!";
                        nextAction = () => showModeSelectionScreen();
                    } else { 
                        buttonText = "Siguiente Nivel (Aislar)";
                        nextAction = () => initLevel(currentLevel + 1);
                    }
                }
                showMessage("¡Felicidades!", `${winMsg} Presiona para continuar.`, buttonText, nextAction);
            }
        }


        function showMessage(title, text, buttonText, callback) {
            messageTitle.textContent = title;
            messageText.textContent = text;
            const newButton = messageButton.cloneNode(true);
            newButton.textContent = buttonText; 
            messageButton.parentNode.replaceChild(newButton, messageButton);
            messageButton = newButton; 
            messageOverlay.classList.remove('hidden'); 
            modeSelectionOverlay.classList.add('hidden'); 
            messageButton.onclick = () => {
                if (messageOverlay) messageOverlay.classList.add('hidden');
                if (callback) callback();
            };
        }

        function updatePlayerPosition(dx, dy) {
            if (!player) return; 
            if (player.edge === 'top') {
                player.x = Math.max(0, Math.min(player.x + dx, CANVAS_WIDTH - PLAYER_SIZE));
            } else if (player.edge === 'bottom') {
                player.x = Math.max(0, Math.min(player.x + dx, CANVAS_WIDTH - PLAYER_SIZE));
            } else if (player.edge === 'left') {
                player.y = Math.max(0, Math.min(player.y + dy, CANVAS_HEIGHT - PLAYER_SIZE));
            } else if (player.edge === 'right') {
                player.y = Math.max(0, Math.min(player.y + dy, CANVAS_HEIGHT - PLAYER_SIZE));
            }
        }
        
        function switchPlayerEdge(key) {
            if (!player) return; 
            if (player.edge === 'top') {
                if (key === 'ArrowLeft' && player.x === 0) player.edge = 'left';
                else if (key === 'ArrowRight' && player.x === CANVAS_WIDTH - PLAYER_SIZE) player.edge = 'right';
            } else if (player.edge === 'bottom') {
                 if (key === 'ArrowLeft' && player.x === 0) { player.edge = 'left'; player.y = CANVAS_HEIGHT - PLAYER_SIZE; }
                 else if (key === 'ArrowRight' && player.x === CANVAS_WIDTH - PLAYER_SIZE) { player.edge = 'right'; player.y = CANVAS_HEIGHT - PLAYER_SIZE; }
            } else if (player.edge === 'left') {
                if (key === 'ArrowUp' && player.y === 0) player.edge = 'top';
                else if (key === 'ArrowDown' && player.y === CANVAS_HEIGHT - PLAYER_SIZE) player.edge = 'bottom';
            } else if (player.edge === 'right') {
                 if (key === 'ArrowUp' && player.y === 0) { player.edge = 'top'; player.x = CANVAS_WIDTH - PLAYER_SIZE; }
                 else if (key === 'ArrowDown' && player.y === CANVAS_HEIGHT - PLAYER_SIZE) { player.edge = 'bottom'; player.x = CANVAS_WIDTH - PLAYER_SIZE; }
            }
        }

        function handleInput(e) {
            if (!player) return; 
            if (gameState !== 'PLAYING' && gameState !== 'READY') return;
            if (gameState === 'READY' && e.key === ' ') { e.preventDefault(); setGameState('PLAYING'); return; }
            if (gameState !== 'PLAYING') return;

            const prevX = player.x; const prevY = player.y;

            if (e.key === 'ArrowLeft') {
                e.preventDefault();
                if (player.edge === 'top' || player.edge === 'bottom') {
                    updatePlayerPosition(-PLAYER_SPEED, 0);
                    if (player.x === prevX && player.x === 0) switchPlayerEdge(e.key); 
                }
            } else if (e.key === 'ArrowRight') {
                e.preventDefault();
                if (player.edge === 'top' || player.edge === 'bottom') {
                    updatePlayerPosition(PLAYER_SPEED, 0);
                    if (player.x === prevX && player.x === CANVAS_WIDTH - PLAYER_SIZE) switchPlayerEdge(e.key);
                }
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                if (player.edge === 'left' || player.edge === 'right') {
                    updatePlayerPosition(0, -PLAYER_SPEED);
                    if (player.y === prevY && player.y === 0) switchPlayerEdge(e.key);
                }
            } else if (e.key === 'ArrowDown') {
                e.preventDefault();
                if (player.edge === 'left' || player.edge === 'right') {
                    updatePlayerPosition(0, PLAYER_SPEED);
                    if (player.y === prevY && player.y === CANVAS_HEIGHT - PLAYER_SIZE) switchPlayerEdge(e.key);
                }
            } else if (e.key === ' ' && !player.drawingLine) { e.preventDefault(); startDrawingLine(); }
        }
        
        function startDrawingLine() {
            if (!player) return; 
            setGameState('DRAWING');
            let startX, startY, endX, endY, orientation, directionFactor;
            const playerCenterX = player.x + PLAYER_SIZE / 2;
            const playerCenterY = player.y + PLAYER_SIZE / 2;
            
            let drawBounds = (gameMode === 'xonix') ? activeArea : {x:0, y:0, width: CANVAS_WIDTH, height: CANVAS_HEIGHT};

            if (player.edge === 'top') {
                startX = playerCenterX; startY = drawBounds.y; 
                endX = playerCenterX; endY = drawBounds.y + drawBounds.height;
                orientation = 'vertical'; directionFactor = 1; 
            } else if (player.edge === 'bottom') {
                startX = playerCenterX; startY = drawBounds.y + drawBounds.height;
                endX = playerCenterX; endY = drawBounds.y;
                orientation = 'vertical'; directionFactor = -1; 
            } else if (player.edge === 'left') {
                startX = drawBounds.x; startY = playerCenterY;
                endX = drawBounds.x + drawBounds.width; endY = playerCenterY;
                orientation = 'horizontal'; directionFactor = 1; 
            } else { 
                startX = drawBounds.x + drawBounds.width; startY = playerCenterY;
                endX = drawBounds.x; endY = playerCenterY;
                orientation = 'horizontal'; directionFactor = -1; 
            }

            player.drawingLine = {
                startX: startX, startY: startY, currentX: startX, currentY: startY,
                targetX: endX, targetY: endY, orientation: orientation,
                directionFactor: directionFactor, color: LINE_COLOR
            };
        }

        function updateDrawingLine() {
            if (!player || !player.drawingLine) return; 
            const line = player.drawingLine;
            const prevCurrentX = line.currentX;
            const prevCurrentY = line.currentY;

            if (line.orientation === 'vertical') {
                line.currentY += LINE_DRAW_SPEED * line.directionFactor;
            } else { 
                line.currentX += LINE_DRAW_SPEED * line.directionFactor;
            }

            if (gameMode === 'isolate') {
                for (let wall of walls) {
                    let intersected = false;
                    if (line.orientation === 'vertical') {
                        if (wall.orientation === 'horizontal' &&
                            line.startX >= Math.min(wall.x1, wall.x2) && line.startX <= Math.max(wall.x1, wall.x2) &&
                            ((prevCurrentY < wall.y1 && line.currentY >= wall.y1) || 
                             (prevCurrentY > wall.y1 && line.currentY <= wall.y1))) { 
                            line.currentY = wall.y1; 
                            intersected = true;
                        }
                    } else { 
                        if (wall.orientation === 'vertical' &&
                            line.startY >= Math.min(wall.y1, wall.y2) && line.startY <= Math.max(wall.y1, wall.y2) &&
                            ((prevCurrentX < wall.x1 && line.currentX >= wall.x1) || 
                             (prevCurrentX > wall.x1 && line.currentX <= wall.x1))) { 
                            line.currentX = wall.x1; 
                            intersected = true;
                        }
                    }
                    if (intersected) {
                        completeLine(); 
                        return; 
                    }
                }
            }

            if (line.orientation === 'vertical') {
                if ((line.directionFactor > 0 && line.currentY >= line.targetY) || (line.directionFactor < 0 && line.currentY <= line.targetY)) {
                    line.currentY = line.targetY; completeLine();
                }
            } else { 
                 if ((line.directionFactor > 0 && line.currentX >= line.targetX) || (line.directionFactor < 0 && line.currentX <= line.targetX)) {
                    line.currentX = line.targetX; completeLine();
                }
            }
            checkLineBallCollision(); 
        }


        function checkLineBallCollision() {
            if (!player || !player.drawingLine) return; 
            const line = player.drawingLine;
            for (let ball of balls) {
                let collision = false;
                const lineThicknessBuffer = 2; 
                if (line.orientation === 'vertical') {
                    const x0 = line.startX; 
                    const y1 = Math.min(line.startY, line.currentY); 
                    const y2 = Math.max(line.startY, line.currentY);
                    if (Math.abs(ball.x - x0) < ball.radius + lineThicknessBuffer && 
                        ball.y + ball.radius > y1 && ball.y - ball.radius < y2) collision = true;
                } else { 
                    const y0 = line.startY; 
                    const x1 = Math.min(line.startX, line.currentX); 
                    const x2 = Math.max(line.startX, line.currentX);
                    if (Math.abs(ball.y - y0) < ball.radius + lineThicknessBuffer && 
                        ball.x + ball.radius > x1 && ball.x - ball.radius < x2) collision = true;
                }
                if (collision) { loseLife(); return; }
            }
        }
        
        function loseLife() {
            lives--; 
            if(player) player.drawingLine = null; 
            updateUI();
            if (lives <= 0) setGameState('GAME_OVER');
            else setGameState('PLAYING'); 
        }
    
        function completeLine() {
            if (!player || !player.drawingLine) return; 
            const line = player.drawingLine;
            player.drawingLine = null; 
    
            if (gameMode === 'xonix') {
                completeLineXonix(line);
            } else { 
                completeLineIsolate(line);
            }
        }
    
        function completeLineXonix(line) {
            let rect1, rect2;
            if (line.orientation === 'vertical') {
                const splitX = line.startX;
                rect1 = { x: activeArea.x, y: activeArea.y, width: splitX - activeArea.x, height: activeArea.height };
                rect2 = { x: splitX, y: activeArea.y, width: (activeArea.x + activeArea.width) - splitX, height: activeArea.height };
            } else { 
                const splitY = line.startY;
                rect1 = { x: activeArea.x, y: activeArea.y, width: activeArea.width, height: splitY - activeArea.y };
                rect2 = { x: activeArea.x, y: splitY, width: activeArea.width, height: (activeArea.y + activeArea.height) - splitY };
            }
            
            const validRects = [rect1, rect2].filter(r => r && r.width > 0.1 && r.height > 0.1);
            if (validRects.length < 2) { setGameState('PLAYING'); return; }
    
            let ballsInRect1 = 0, ballsInRect2 = 0;
            for (let ball of balls) {
                if (rect1.width > 0.1 && rect1.height > 0.1 && isBallInRect(ball, rect1)) ballsInRect1++;
                else if (rect2.width > 0.1 && rect2.height > 0.1 && isBallInRect(ball, rect2)) ballsInRect2++;
            }
            
            let filledNewArea = false, areaToKeep = null;
            if (rect1.width > 0.1 && rect1.height > 0.1 && ballsInRect1 === 0) {
                filledAreas.push(rect1); areaToKeep = rect2; 
                if (!(areaToKeep.width > 0.1 && areaToKeep.height > 0.1)) areaToKeep = null;
                filledNewArea = true;
            } else if (rect2.width > 0.1 && rect2.height > 0.1 && ballsInRect2 === 0) {
                filledAreas.push(rect2); areaToKeep = rect1; 
                if (!(areaToKeep.width > 0.1 && areaToKeep.height > 0.1)) areaToKeep = null;
                filledNewArea = true;
            }
    
            if (filledNewArea && areaToKeep) {
                activeArea = areaToKeep; repositionPlayerToActiveAreaXonix(); calculateConqueredArea();
                if (conqueredAreaPercentage >= TARGET_AREA_PERCENTAGE) {
                    setGameState('GAME_WON'); 
                    return; 
                }
            }
            setGameState('PLAYING');
        }
    
        function completeLineIsolate(line) {
            const newWall = {
                x1: line.startX, y1: line.startY, x2: line.currentX, y2: line.currentY,
                orientation: line.orientation
            };
            
            if ((newWall.orientation === 'vertical' && Math.abs(newWall.y1 - newWall.y2) < PLAYER_SIZE / 2) ||
                (newWall.orientation === 'horizontal' && Math.abs(newWall.x1 - newWall.x2) < PLAYER_SIZE / 2)) {
                setGameState('PLAYING');
                return;
            }
    
            walls.push(newWall);
            checkWinConditionIsolate(); 
            if (gameState !== 'GAME_WON' && gameState !== 'GAME_OVER') { 
                 setGameState('PLAYING');
            }
        }
        
        function checkWinConditionIsolate() {
            if (balls.length === 0 && walls.length > 0) { 
                 setGameState('GAME_WON'); return; 
            }
            if (balls.length === 0 && walls.length === 0) return; 
    
            const ballCells = []; 
            for (let i = 0; i < balls.length; i++) {
                const ball = balls[i];
                let minX = 0, maxX = CANVAS_WIDTH;
                let minY = 0, maxY = CANVAS_HEIGHT;
    
                for (let wall of walls) {
                    if (wall.orientation === 'vertical') {
                        const wallX = wall.x1; 
                        const wallSegmentMinY = Math.min(wall.y1, wall.y2);
                        const wallSegmentMaxY = Math.max(wall.y1, wall.y2);
                        if (ball.y >= wallSegmentMinY && ball.y <= wallSegmentMaxY) { 
                            if (wallX < ball.x && wallX > minX) minX = wallX; 
                            if (wallX > ball.x && wallX < maxX) maxX = wallX; 
                        }
                    } else { 
                        const wallY = wall.y1; 
                        const wallSegmentMinX = Math.min(wall.x1, wall.x2);
                        const wallSegmentMaxX = Math.max(wall.x1, wall.x2);
                        if (ball.x >= wallSegmentMinX && ball.x <= wallSegmentMaxX) { 
                            if (wallY < ball.y && wallY > minY) minY = wallY; 
                            if (wallY > ball.y && wallY < maxY) maxY = wallY; 
                        }
                    }
                }
                
                if (maxX - minX < BALL_RADIUS*1.5 || maxY - minY < BALL_RADIUS*1.5) { 
                }
    
                const cellId = `${minX.toFixed(1)}-${minY.toFixed(1)}-${maxX.toFixed(1)}-${maxY.toFixed(1)}`;
                ball.cell = cellId; 
                
                for (let j = 0; j < ballCells.length; j++) {
                    if (ballCells[j] === cellId) {
                        return; 
                    }
                }
                ballCells.push(cellId);
            }
            setGameState('GAME_WON'); 
        }
    
        function repositionPlayerToActiveAreaXonix() { 
            if (!player) return; 
            player.edge = 'top'; 
            player.x = activeArea.x + activeArea.width / 2 - PLAYER_SIZE / 2;
            player.y = activeArea.y;
            player.x = Math.max(activeArea.x, Math.min(player.x, activeArea.x + activeArea.width - PLAYER_SIZE));
            player.y = Math.max(activeArea.y, Math.min(player.y, activeArea.y + activeArea.height - PLAYER_SIZE));
            if (player.edge === 'top') player.y = activeArea.y;
            else if (player.edge === 'bottom') player.y = activeArea.y + activeArea.height - PLAYER_SIZE;
            else if (player.edge === 'left') player.x = activeArea.x;
            else if (player.edge === 'right') player.x = activeArea.x + activeArea.width - PLAYER_SIZE;
        }
    
        function isBallInRect(ball, rect) { 
            if (!rect) return false;
            return ball.x - ball.radius >= rect.x && ball.x + ball.radius <= rect.x + rect.width &&
                   ball.y - ball.radius >= rect.y && ball.y + ball.radius <= rect.y + rect.height;
        }
    
        function calculateConqueredArea() { 
            let currentFilledAreaSum = 0;
            for (let area of filledAreas) { currentFilledAreaSum += area.width * area.height; }
            conqueredAreaPercentage = (currentFilledAreaSum / totalCanvasArea) * 100;
            updateUI();
        }
    
        function updateUI() {
            modeDisplay.textContent = gameMode === 'xonix' ? 'Xonix' : 'Aislar';
            levelDisplay.textContent = currentLevel || 1; 
            livesDisplay.textContent = (typeof lives === 'number') ? lives : INITIAL_LIVES; 
            areaDisplay.textContent = (gameMode === 'xonix') ? `${Math.floor(conqueredAreaPercentage || 0)}%` : '-';
        }
    
        function draw() {
            ctx.fillStyle = ACTIVE_AREA_COLOR;
            ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
    
            if (gameMode === 'xonix' && filledAreas) { 
                ctx.fillStyle = FILLED_AREA_COLOR;
                for (let area of filledAreas) { ctx.fillRect(area.x, area.y, area.width, area.height); }
            } else if (gameMode === 'isolate' && walls) { 
                ctx.strokeStyle = WALL_COLOR;
                ctx.lineWidth = 2; 
                for (let wall of walls) {
                    ctx.beginPath();
                    ctx.moveTo(wall.x1, wall.y1);
                    ctx.lineTo(wall.x2, wall.y2);
                    ctx.stroke();
                }
            }
            
            if ((gameState === 'PLAYING' || gameState === 'DRAWING' || gameState === 'READY') && balls) { 
                for (let ball of balls) { ball.draw(); }
            }
    
            if (player && (gameState === 'PLAYING' || gameState === 'DRAWING')) {
                 ctx.fillStyle = PLAYER_COLOR;
                 ctx.fillRect(player.x, player.y, PLAYER_SIZE, PLAYER_SIZE);
            }
    
            if (player && player.drawingLine) { 
                const line = player.drawingLine;
                ctx.beginPath(); ctx.moveTo(line.startX, line.startY); ctx.lineTo(line.currentX, line.currentY);
                ctx.strokeStyle = line.color; ctx.lineWidth = 2; ctx.stroke(); ctx.closePath();
            }
        }
    
        function gameLoop() {
            if ((gameState === 'PLAYING' || gameState === 'DRAWING') && balls) { 
                balls.forEach(ball => ball.update());
            }
            if (gameState === 'DRAWING') {
                updateDrawingLine();
            }
            
            if (gameState !== 'MODE_SELECT' || (gameState === 'MODE_SELECT' && modeSelectionOverlay.classList.contains('hidden'))) {
                 draw();
            } else if (gameState === 'MODE_SELECT') { 
                ctx.fillStyle = ACTIVE_AREA_COLOR;
                ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
            }
    
            requestAnimationFrame(gameLoop);
        }
    
        modeXonixButton.addEventListener('click', () => {
            gameMode = 'xonix';
            modeDisplay.textContent = 'Xonix';
            modeSelectionOverlay.classList.add('hidden');
            startGame();
        });
    
        modeIsolateButton.addEventListener('click', () => {
            gameMode = 'isolate';
            modeDisplay.textContent = 'Aislar';
            modeSelectionOverlay.classList.add('hidden');
            startGame();
        });
        
        document.addEventListener('keydown', handleInput);
        
        showModeSelectionScreen();
        requestAnimationFrame(gameLoop);
    </script>
</body>
</html>