🎮ArcadeLab

Game Catur Emoji dengan AI

by NovaViper78
489 lines16.7 KB
▶ Play
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Game Catur Emoji dengan AI</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #1e1e2f, #2d2b42);
            color: #ffffff;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            margin: 0;
        }

        h1 {
            margin-bottom: 5px;
            font-size: 1.8rem;
            color: #f1f1f1;
        }

        .controls {
            margin-bottom: 15px;
            display: flex;
            gap: 10px;
            align-items: center;
            flex-wrap: wrap;
            justify-content: center;
        }

        select, button {
            padding: 8px 14px;
            font-size: 0.95rem;
            border-radius: 6px;
            border: none;
            background-color: #4e4376;
            color: white;
            cursor: pointer;
            transition: background 0.2s;
        }

        select:hover, button:hover {
            background-color: #5b4f88;
        }

        #status {
            margin-bottom: 15px;
            font-size: 1.1rem;
            font-weight: bold;
            color: #ffcc00;
            min-height: 25px;
            text-align: center;
        }

        #board {
            display: grid;
            grid-template-columns: repeat(8, 55px);
            grid-template-rows: repeat(8, 55px);
            border: 4px solid #443c68;
            box-shadow: 0 8px 20px rgba(0,0,0,0.5);
            border-radius: 4px;
        }

        .square {
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 32px;
            cursor: pointer;
            user-select: none;
            transition: background-color 0.15s;
        }

        .light {
            background-color: #f0d9b5;
        }

        .dark {
            background-color: #b58863;
        }

        .selected {
            background-color: #baca44 !important;
        }

        .highlight {
            background-color: #79a632 !important;
        }

        @media (max-width: 500px) {
            #board {
                grid-template-columns: repeat(8, 42px);
                grid-template-rows: repeat(8, 42px);
            }
            .square {
                font-size: 24px;
            }
        }
    </style>
</head>
<body>

    <h1>♟️ Game Catur Emoji AI</h1>
    
    <div class="controls">
        <label for="difficulty">Level AI:</label>
        <select id="difficulty">
            <option value="easy">Mudah (Pemula)</option>
            <option value="hard" selected>Sulit (Ahli)</option>
        </select>
        <button onclick="resetGame()">Mulai Baru</button>
    </div>

    <div id="status">Giliran Anda (Putih ⚪)</div>
    <div id="board"></div>

    <script>
        // Inisialisasi Audio Web API untuk efek suara
        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        function playSound(type) {
            if (audioCtx.state === 'suspended') audioCtx.resume();
            const osc = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            osc.connect(gain);
            gain.connect(audioCtx.destination);
            
            let now = audioCtx.currentTime;
            if (type === 'move') {
                osc.frequency.setValueAtTime(400, now);
                gain.gain.setValueAtTime(0.1, now);
                gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
                osc.start(now);
                osc.stop(now + 0.1);
            } else if (type === 'capture') {
                osc.frequency.setValueAtTime(200, now);
                osc.frequency.exponentialRampToValueAtTime(600, now + 0.15);
                gain.gain.setValueAtTime(0.15, now);
                gain.gain.exponentialRampToValueAtTime(0.01, now + 0.15);
                osc.start(now);
                osc.stop(now + 0.15);
            } else if (type === 'end') {
                osc.frequency.setValueAtTime(523.25, now);
                osc.frequency.setValueAtTime(659.25, now + 0.1);
                osc.frequency.setValueAtTime(783.99, now + 0.2);
                gain.gain.setValueAtTime(0.1, now);
                gain.gain.exponentialRampToValueAtTime(0.01, now + 0.4);
                osc.start(now);
                osc.stop(now + 0.4);
            }
        }

        // Simbol Buah Catur (Putih vs Hitam)
        const pieces = {
            'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔', 'P': '♙',
            'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚', 'p': '♟'
        };

        let board = [
            ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
            ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
            ['', '', '', '', '', '', '', ''],
            ['', '', '', '', '', '', '', ''],
            ['', '', '', '', '', '', '', ''],
            ['', '', '', '', '', '', '', ''],
            ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
            ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
        ];

        let turn = 'w'; // 'w' untuk putih (pemain), 'b' untuk hitam (AI)
        let selectedSquare = null;
        let validMoves = [];
        let gameOver = false;

        function isWhite(piece) {
            return piece && piece === piece.toUpperCase();
        }

        function isBlack(piece) {
            return piece && piece === piece.toLowerCase();
        }

        function createBoardUI() {
            const boardEl = document.getElementById('board');
            boardEl.innerHTML = '';
            for (let r = 0; r < 8; r++) {
                for (let c = 0; c < 8; c++) {
                    const square = document.createElement('div');
                    square.className = `square ${(r + c) % 2 === 0 ? 'light' : 'dark'}`;
                    square.dataset.row = r;
                    square.dataset.col = c;
                    
                    const piece = board[r][c];
                    if (piece) {
                        square.textContent = pieces[piece];
                    }

                    if (selectedSquare && selectedSquare.r === r && selectedSquare.c === c) {
                        square.classList.add('selected');
                    }

                    if (validMoves.some(m => m.r === r && m.c === c)) {
                        square.classList.add('highlight');
                    }

                    square.addEventListener('click', () => handleSquareClick(r, c));
                    boardEl.appendChild(square);
                }
            }
        }

        function handleSquareClick(r, c) {
            if (gameOver || turn !== 'w') return;

            const piece = board[r][c];

            if (selectedSquare) {
                // Jika mengklik langkah yang valid, jalankan gerakan
                const move = validMoves.find(m => m.r === r && m.c === c);
                if (move) {
                    executeMove(selectedSquare.r, selectedSquare.c, r, c);
                    selectedSquare = null;
                    validMoves = [];
                    createBoardUI();
                    
                    if (!gameOver) {
                        turn = 'b';
                        document.getElementById('status').textContent = "AI sedang berpikir... 🤖";
                        setTimeout(aiTurn, 400);
                    }
                    return;
                }
            }

            // Pilih buah catur milik pemain (Putih)
            if (piece && isWhite(piece)) {
                selectedSquare = { r, c };
                validMoves = getValidMoves(r, c, board);
                createBoardUI();
            } else {
                selectedSquare = null;
                validMoves = [];
                createBoardUI();
            }
        }

        function executeMove(sr, sc, dr, dc) {
            const target = board[dr][dc];
            board[dr][dc] = board[sr][sc];
            board[sr][sc] = '';

            // Promosi pion sederhana menjadi ratu
            if (board[dr][dc] === 'P' && dr === 0) board[dr][dc] = 'Q';
            if (board[dr][dc] === 'p' && dr === 7) board[dr][dc] = 'q';

            if (target) {
                playSound('capture');
            } else {
                playSound('move');
            }

            checkGameEnd();
        }

        // Logika Aturan Pergerakan Dasar Catur
        function getValidMoves(r, c, currentBoard) {
            const piece = currentBoard[r][c];
            const moves = [];
            if (!piece) return moves;

            const isW = isWhite(piece);
            const type = piece.toLowerCase();

            function addSlideMoves(directions) {
                for (let d of directions) {
                    let nr = r + d[0];
                    let nc = c + d[1];
                    while (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
                        const target = currentBoard[nr][nc];
                        if (!target) {
                            moves.push({ r: nr, c: nc });
                        } else {
                            if (isW !== isWhite(target)) moves.push({ r: nr, c: nc });
                            break;
                        }
                        nr += d[0];
                        nc += d[1];
                    }
                }
            }

            if (type === 'p') {
                const dir = isW ? -1 : 1;
                const startRow = isW ? 6 : 1;
                // Maju 1 langkah
                if (r + dir >= 0 && r + dir < 8 && !currentBoard[r + dir][c]) {
                    moves.push({ r: r + dir, c: c });
                    // Maju 2 langkah dari posisi awal
                    if (r === startRow && !currentBoard[r + 2 * dir][c]) {
                        moves.push({ r: r + 2 * dir, c: c });
                    }
                }
                // Makan diagonal
                for (let dc of [-1, 1]) {
                    let nc = c + dc;
                    let nr = r + dir;
                    if (nc >= 0 && nc < 8 && nr >= 0 && nr < 8) {
                        const target = currentBoard[nr][nc];
                        if (target && isW !== isWhite(target)) {
                            moves.push({ r: nr, c: nc });
                        }
                    }
                }
            } else if (type === 'n') {
                const knightMoves = [
                    [-2, -1], [-2, 1], [-1, -2], [-1, 2],
                    [1, -2], [1, 2], [2, -1], [2, 1]
                ];
                for (let m of knightMoves) {
                    let nr = r + m[0], nc = c + m[1];
                    if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
                        const target = currentBoard[nr][nc];
                        if (!target || isW !== isWhite(target)) {
                            moves.push({ r: nr, c: nc });
                        }
                    }
                }
            } else if (type === 'b') {
                addSlideMoves([[-1, -1], [-1, 1], [1, -1], [1, 1]]);
            } else if (type === 'r') {
                addSlideMoves([[-1, 0], [1, 0], [0, -1], [0, 1]]);
            } else if (type === 'q') {
                addSlideMoves([[-1, -1], [-1, 1], [1, -1], [1, 1], [-1, 0], [1, 0], [0, -1], [0, 1]]);
            } else if (type === 'k') {
                const kingMoves = [
                    [-1, -1], [-1, 0], [-1, 1],
                    [0, -1], [0, 1],
                    [1, -1], [1, 0], [1, 1]
                ];
                for (let m of kingMoves) {
                    let nr = r + m[0], nc = c + m[1];
                    if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
                        const target = currentBoard[nr][nc];
                        if (!target || isW !== isWhite(target)) {
                            moves.push({ r: nr, c: nc });
                        }
                    }
                }
            }
            return moves;
        }

        function getAllPossibleMoves(playerColor, currentBoard) {
            let allMoves = [];
            for (let r = 0; r < 8; r++) {
                for (let c = 0; c < 8; c++) {
                    const piece = currentBoard[r][c];
                    if (piece && (playerColor === 'w' ? isWhite(piece) : isBlack(piece))) {
                        const moves = getValidMoves(r, c, currentBoard);
                        for (let m of moves) {
                            allMoves.push({ sr: r, sc: c, dr: m.r, dc: m.c });
                        }
                    }
                }
            }
            return allMoves;
        }

        // AI Logic: Mudah & Sulit
        const pieceValues = { p: 10, n: 30, b: 30, r: 50, q: 90, k: 900 };

        function evaluateBoard(currentBoard) {
            let score = 0;
            for (let r = 0; r < 8; r++) {
                for (let c = 0; c < 8; c++) {
                    const p = currentBoard[r][c];
                    if (p) {
                        let val = pieceValues[p.toLowerCase()] || 0;
                        if (isBlack(p)) score += val;
                        else score -= val;
                    }
                }
            }
            return score;
        }

        function aiTurn() {
            if (gameOver) return;
            const difficulty = document.getElementById('difficulty').value;
            const allMoves = getAllPossibleMoves('b', board);

            if (allMoves.length === 0) {
                checkGameEnd();
                return;
            }

            let chosenMove = null;

            if (difficulty === 'easy') {
                // Pilih langkah acak
                chosenMove = allMoves[Math.floor(Math.random() * allMoves.length)];
            } else {
                // Sulit: Evaluasi langkah terbaik (Greedy + menangkap prioritas tinggi)
                let bestScore = -99999;
                let scoredMoves = [];

                for (let m of allMoves) {
                    // Simulasi langkah
                    let tempTarget = board[m.dr][m.dc];
                    board[m.dr][m.dc] = board[m.sr][m.sc];
                    board[m.sr][m.sc] = '';

                    let score = evaluateBoard(board);
                    
                    // Kembalikan papan
                    board[m.sr][m.sc] = board[m.dr][m.dc];
                    board[m.dr][m.dc] = tempTarget;

                    if (score > bestScore) {
                        bestScore = score;
                        scoredMoves = [m];
                    } else if (score === bestScore) {
                        scoredMoves.push(m);
                    }
                }
                // Ambil salah satu dari langkah dengan skor terbaik
                chosenMove = scoredMoves[Math.floor(Math.random() * scoredMoves.length)];
            }

            if (chosenMove) {
                executeMove(chosenMove.sr, chosenMove.sc, chosenMove.dr, chosenMove.dc);
            }

            if (!gameOver) {
                turn = 'w';
                document.getElementById('status').textContent = "Giliran Anda (Putih ⚪)";
            }
            createBoardUI();
        }

        function checkGameEnd() {
            let whiteKing = false;
            let blackKing = false;

            for (let r = 0; r < 8; r++) {
                for (let c = 0; c < 8; c++) {
                    if (board[r][c] === 'K') whiteKing = true;
                    if (board[r][c] === 'k') blackKing = true;
                }
            }

            if (!whiteKing) {
                gameOver = true;
                document.getElementById('status').textContent = "Game Selesai! AI Hitam Menang 🤖";
                playSound('end');
            } else if (!blackKing) {
                gameOver = true;
                document.getElementById('status').textContent = "Selamat! Anda Menang 🎉";
                playSound('end');
            }
        }

        function resetGame() {
            board = [
                ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
                ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
                ['', '', '', '', '', '', '', ''],
                ['', '', '', '', '', '', '', ''],
                ['', '', '', '', '', '', '', ''],
                ['', '', '', '', '', '', '', ''],
                ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
                ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
            ];
            turn = 'w';
            selectedSquare = null;
            validMoves = [];
            gameOver = false;
            document.getElementById('status').textContent = "Giliran Anda (Putih ⚪)";
            createBoardUI();
        }

        // Render awal saat halaman dimuat
        createBoardUI();
    </script>
</body>
</html>

Game Source: Game Catur Emoji dengan AI

Creator: NovaViper78

Libraries: none

Complexity: complex (489 lines, 16.7 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: game-catur-emoji-dengan-ai-novaviper78" to link back to the original. Then publish at arcadelab.ai/publish.