🎮ArcadeLab

Math Match 1.0 - VideojuCan

by CosmicCobra59
473 lines16.6 KB
▶ Play
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Math Match 1.0 - VideojuCan</title>
    <style>
        :root {
            --bg: #1a1a2e;
            --card: #16213e;
            --primary: #e94560;
            --secondary: #0f3460;
            --text: #eee;
            --muted: #aaa;
            --border: #2a2a4a;
            --success: #2ecc71;
            --gold: #f1c40f;
        }
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            background: var(--bg);
            color: var(--text);
            font-family: 'Segoe UI', 'Courier New', monospace;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            touch-action: manipulation;
            user-select: none;
            -webkit-user-select: none;
        }
        #gameContainer {
            width: 100%;
            max-width: 500px;
            background: var(--card);
            border-radius: 20px;
            padding: 1.5rem;
            border: 2px solid var(--primary);
            box-shadow: 0 0 30px rgba(233,68,96,0.3);
            text-align: center;
        }
        h1 {
            font-size: 2rem;
            color: var(--gold);
            margin-bottom: 0.5rem;
        }
        .battle-area {
            display: flex;
            justify-content: space-around;
            align-items: center;
            margin: 1rem 0;
        }
        .player-box {
            text-align: center;
            padding: 1rem;
            border-radius: 12px;
            border: 2px solid var(--border);
            min-width: 120px;
            transition: all 0.3s;
        }
        .player-box.active {
            border-color: var(--gold);
            box-shadow: 0 0 15px rgba(241,196,15,0.4);
        }
        .player-name {
            font-weight: bold;
            font-size: 1.1rem;
        }
        .player-hp {
            font-size: 2rem;
            color: var(--success);
            margin: 0.3rem 0;
        }
        .player-hp.danger { color: #e74c3c; }
        .vs-text {
            font-size: 1.5rem;
            font-weight: bold;
            color: var(--gold);
        }
        .phase-info {
            color: var(--muted);
            font-size: 0.9rem;
            margin: 0.5rem 0;
        }
        .number-pad {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
            justify-content: center;
            margin: 1rem 0;
        }
        .num-btn {
            width: 55px;
            height: 55px;
            border-radius: 12px;
            border: 2px solid var(--border);
            background: var(--secondary);
            color: var(--text);
            font-size: 1.4rem;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s;
        }
        .num-btn:hover:not(:disabled) {
            border-color: var(--primary);
            background: var(--primary);
            color: #fff;
            transform: scale(1.05);
        }
        .num-btn:disabled {
            opacity: 0.3;
            cursor: not-allowed;
        }
        .num-uses {
            font-size: 0.7rem;
            color: var(--muted);
            margin-top: -0.3rem;
        }
        .uses-bar {
            width: 40px;
            height: 4px;
            background: #333;
            border-radius: 2px;
            margin: 2px auto;
            overflow: hidden;
        }
        .uses-fill {
            height: 100%;
            border-radius: 2px;
            transition: width 0.3s;
        }
        .sword-btn {
            font-family: inherit;
            padding: 0.6rem 1.5rem;
            border-radius: 10px;
            border: 2px solid var(--gold);
            background: #8b4513;
            color: var(--gold);
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            margin: 0.5rem;
            animation: pulse 1.5s infinite;
        }
        @keyframes pulse {
            0%, 100% { box-shadow: 0 0 10px rgba(241,196,15,0.4); }
            50% { box-shadow: 0 0 20px rgba(241,196,15,0.8); }
        }
        .sword-btn:disabled {
            opacity: 0.4;
            animation: none;
            cursor: not-allowed;
        }
        .btn {
            font-family: inherit;
            padding: 0.6rem 1.5rem;
            border-radius: 10px;
            border: none;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            margin: 0.3rem;
            transition: all 0.2s;
        }
        .btn-primary { background: var(--primary); color: #fff; }
        .btn-outline { background: transparent; border: 2px solid var(--primary); color: var(--primary); }
        .victory-text {
            font-size: 1.5rem;
            color: var(--gold);
            font-weight: bold;
            margin: 1rem 0;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 0.5rem;
            margin: 1rem 0;
            font-size: 0.85rem;
            color: var(--muted);
        }
        .hidden { display: none !important; }
        @media (max-width: 400px) {
            .num-btn { width: 42px; height: 42px; font-size: 1.1rem; }
        }
    </style>
</head>
<body>

    <div id="gameContainer">
        <h1>⚔️ MATH MATCH</h1>

        <!-- MENÚ -->
        <div id="menuScreen">
            <p style="color:var(--muted);">Elige modo de juego</p>
            <button class="btn btn-primary" onclick="startGame('pvp')">👥 1 vs 1 Local</button>
            <br>
            <button class="btn btn-outline" onclick="startGame('bot')">🤖 vs Bot</button>
        </div>

        <!-- BATALLA -->
        <div id="battleScreen" class="hidden">
            <div class="battle-area">
                <div class="player-box" id="player1Box">
                    <div class="player-name" id="p1Name">Orco 1</div>
                    <div class="player-hp" id="p1Hp">1</div>
                </div>
                <div class="vs-text">VS</div>
                <div class="player-box" id="player2Box">
                    <div class="player-name" id="p2Name">Orco 2</div>
                    <div class="player-hp" id="p2Hp">1</div>
                </div>
            </div>
            <div class="phase-info" id="phaseInfo"></div>
            <div id="turnInfo" style="color:var(--gold); font-weight:bold; margin:0.5rem;"></div>
            <div class="number-pad" id="numberPad"></div>
            <button class="sword-btn hidden" id="swordBtn" onclick="useSword()">🗡️ Espada de Suma (5)</button>
            <button class="btn btn-outline" onclick="backToMenu()" style="margin-top:1rem;">⬅️ Menú</button>
        </div>

        <!-- VICTORIA -->
        <div id="victoryScreen" class="hidden">
            <div class="victory-text" id="victoryText"></div>
            <div class="stats-grid" id="statsGrid"></div>
            <button class="btn btn-primary" onclick="restartGame()">🔄 Revancha</button>
            <button class="btn btn-outline" onclick="backToMenu()">⬅️ Menú</button>
        </div>
    </div>

    <script>
        // ========== ESTADO DEL JUEGO ==========
        const MAX_USES = { 1: 10, 2: 10, 3: 10, 4: 10, 5: 10, 6: 10, 7: 10, 8: 5, 9: 5 };
        let players = {};
        let game = {
            mode: 'pvp',
            turn: 1,
            phase: 'attack', // 'attack' | 'defend'
            currentAttacker: 1,
            currentDefender: 2,
            attackValue: 0,
            swordBonus: 0,
            gameOver: false,
            stats: { turns: 0, swordUses: 0, biggestHit: 0, numbersUsed: [] }
        };

        function initPlayers() {
            players = {
                1: { name: 'Orco 1', hp: 1, numbers: { ...MAX_USES }, swordUses: 5 },
                2: { name: 'Orco 2', hp: 1, numbers: { ...MAX_USES }, swordUses: 5 }
            };
            game.turn = 1;
            game.phase = 'attack';
            game.currentAttacker = 1;
            game.currentDefender = 2;
            game.attackValue = 0;
            game.swordBonus = 0;
            game.gameOver = false;
            game.stats = { turns: 0, swordUses: 0, biggestHit: 0, numbersUsed: [] };
        }

        // ========== UI ==========
        function showScreen(id) {
            document.getElementById('menuScreen').classList.add('hidden');
            document.getElementById('battleScreen').classList.add('hidden');
            document.getElementById('victoryScreen').classList.add('hidden');
            document.getElementById(id).classList.remove('hidden');
        }

        function startGame(mode) {
            game.mode = mode;
            initPlayers();
            showScreen('battleScreen');
            renderBattle();
        }

        function backToMenu() {
            showScreen('menuScreen');
        }

        function restartGame() {
            startGame(game.mode);
        }

        // ========== RENDERIZADO ==========
        function renderBattle() {
            if (game.gameOver) return;

            const atk = players[game.currentAttacker];
            const def = players[game.currentDefender];

            // Nombres
            document.getElementById('p1Name').textContent = players[1].name;
            document.getElementById('p2Name').textContent = players[2].name;

            // HP
            const hp1 = document.getElementById('p1Hp');
            const hp2 = document.getElementById('p2Hp');
            hp1.textContent = players[1].hp;
            hp2.textContent = players[2].hp;
            hp1.className = 'player-hp' + (players[1].hp < 5 ? ' danger' : '');
            hp2.className = 'player-hp' + (players[2].hp < 5 ? ' danger' : '');

            // Activo
            document.getElementById('player1Box').classList.toggle('active', game.currentAttacker === 1 || game
                .currentDefender === 1);
            document.getElementById('player2Box').classList.toggle('active', game.currentAttacker === 2 || game
                .currentDefender === 2);

            // Fase
            const defHp = def.hp;
            const phaseLabel = defHp < 10 ?
                'Fase 1: Ataque (Resta) / Defensa (Suma)' :
                'Fase 2: Ataque (División) / Defensa (Multiplicación)';
            document.getElementById('phaseInfo').textContent = phaseLabel;

            // Turno
            const action = game.phase === 'attack' ? 'ATACA' : 'DEFIENDE';
            document.getElementById('turnInfo').textContent =
                `TURNO ${game.turn} — ${atk.name} ${action}`;

            // Números
            renderNumberPad(atk.numbers);

            // Espada
            const swordBtn = document.getElementById('swordBtn');
            if (atk.hp >= 100 && atk.swordUses > 0 && game.phase === 'attack') {
                swordBtn.classList.remove('hidden');
                swordBtn.textContent = `🗡️ Espada de Suma (${atk.swordUses})`;
            } else {
                swordBtn.classList.add('hidden');
            }

            // Bot IA
            if (game.mode === 'bot' && game.currentAttacker === 2 && game.phase === 'attack') {
                setTimeout(botAttack, 600);
            }
            if (game.mode === 'bot' && game.currentDefender === 2 && game.phase === 'defend') {
                setTimeout(botDefend, 600);
            }
        }

        function renderNumberPad(pool) {
            const pad = document.getElementById('numberPad');
            pad.innerHTML = '';
            for (let i = 1; i <= 9; i++) {
                const uses = pool[i] || 0;
                const max = MAX_USES[i];
                const pct = (uses / max) * 100;
                const barColor = uses <= 2 ? '#e74c3c' : uses <= 5 ? '#f39c12' : '#2ecc71';

                const wrapper = document.createElement('div');
                wrapper.style.textAlign = 'center';

                const btn = document.createElement('button');
                btn.className = 'num-btn';
                btn.textContent = i;
                btn.disabled = uses <= 0 || game.gameOver;
                btn.onclick = () => pickNumber(i);
                wrapper.appendChild(btn);

                const bar = document.createElement('div');
                bar.className = 'uses-bar';
                const fill = document.createElement('div');
                fill.className = 'uses-fill';
                fill.style.width = pct + '%';
                fill.style.background = barColor;
                bar.appendChild(fill);
                wrapper.appendChild(bar);

                const label = document.createElement('div');
                label.className = 'num-uses';
                label.textContent = uses;
                wrapper.appendChild(label);

                pad.appendChild(wrapper);
            }
        }

        // ========== LÓGICA DE JUEGO ==========
        function pickNumber(num) {
            if (game.gameOver) return;
            const player = game.phase === 'attack' ? players[game.currentAttacker] : players[game.currentDefender];
            if (player.numbers[num] <= 0) return;

            player.numbers[num]--;
            game.stats.numbersUsed.push(num);

            if (game.phase === 'attack') {
                game.attackValue = num + game.swordBonus;
                if (game.swordBonus > 0) game.stats.swordUses++;
                if (game.attackValue > game.stats.biggestHit) game.stats.biggestHit = game.attackValue;
                game.swordBonus = 0;
                game.phase = 'defend';
                renderBattle();
            } else {
                resolveTurn(num);
            }
        }

        function useSword() {
            const atk = players[game.currentAttacker];
            if (atk.hp < 100 || atk.swordUses <= 0 || game.phase !== 'attack') return;
            game.swordBonus = Math.random() < 0.5 ? 1 : 2;
            atk.swordUses--;
            document.getElementById('swordBtn').textContent =
                `🗡️ Espada (+${game.swordBonus})`;
        }

        function resolveTurn(defNum) {
            const atk = players[game.currentAttacker];
            const def = players[game.currentDefender];
            let newHp;

            if (def.hp < 10) {
                // Fase 1: suma y resta
                newHp = def.hp + defNum - game.attackValue;
            } else {
                // Fase 2: multiplicación y división
                const divisor = game.attackValue === 0 ? 1 : game.attackValue;
                newHp = Math.max(1, Math.floor(def.hp * defNum / divisor));
            }

            def.hp = Math.max(0, newHp);
            game.attackValue = 0;
            game.stats.turns++;

            // ¿Victoria?
            if (def.hp <= 0) {
                game.gameOver = true;
                const winner = players[game.currentAttacker];
                document.getElementById('victoryText').textContent =
                    `🏆 ¡${winner.name} GANA! 🏆`;
                document.getElementById('statsGrid').innerHTML = `
                    <div>🔄 Turnos: ${game.stats.turns}</div>
                    <div>💥 Mayor golpe: ${game.stats.biggestHit}</div>
                    <div>🗡️ Espadas: ${game.stats.swordUses}</div>
                    <div>🔢 Números usados: ${game.stats.numbersUsed.length}</div>
                `;
                showScreen('victoryScreen');
                return;
            }

            // Cambiar turno
            game.turn++;
            game.currentAttacker = game.currentAttacker === 1 ? 2 : 1;
            game.currentDefender = game.currentAttacker === 1 ? 2 : 1;
            game.phase = 'attack';
            renderBattle();
        }

        function botAttack() {
            if (game.gameOver || game.currentAttacker !== 2 || game.phase !== 'attack') return;
            const pool = players[2].numbers;
            const available = Object.entries(pool).filter(([, c]) => c > 0).map(([n]) => Number(n));
            if (available.length === 0) return;
            const pick = available[Math.floor(Math.random() * available.length)];
            pickNumber(pick);
        }

        function botDefend() {
            if (game.gameOver || game.currentDefender !== 2 || game.phase !== 'defend') return;
            const pool = players[2].numbers;
            const available = Object.entries(pool).filter(([, c]) => c > 0).map(([n]) => Number(n));
            if (available.length === 0) return;
            const pick = available[Math.floor(Math.random() * available.length)];
            pickNumber(pick);
        }

        // ========== INICIALIZAR ==========
        initPlayers();
        showScreen('menuScreen');
    </script>
</body>
</html>

Game Source: Math Match 1.0 - VideojuCan

Creator: CosmicCobra59

Libraries: none

Complexity: complex (473 lines, 16.6 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: math-match-1-0-videojucan-cosmiccobra59" to link back to the original. Then publish at arcadelab.ai/publish.