🎮ArcadeLab

Mein Schachbot Deluxe

by BlazeKoala99
404 lines14.6 KB
▶ Play
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mein Schachbot Deluxe</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.css">
    <style>
        body {
            font-family: 'Segoe UI', Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            background-color: #eef2f3;
            margin: 0;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 5px;
            user-select: none;
        }
        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            background: white;
            padding: 20px;
            border-radius: 12px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.1);
        }
        .controls-row {
            display: flex;
            gap: 15px;
            margin-bottom: 15px;
            flex-wrap: wrap;
            justify-content: center;
        }
        .control-group {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        label {
            font-size: 0.85rem;
            color: #7f8c8d;
            font-weight: bold;
        }
        select, button {
            padding: 8px 12px;
            font-size: 0.95rem;
            border-radius: 6px;
            border: 1px solid #ccc;
            background-color: #fff;
            cursor: pointer;
            transition: all 0.2s;
        }
        select:hover, button:hover {
            border-color: #3498db;
            background-color: #f7f9fa;
        }
        button.primary {
            background-color: #3498db;
            color: white;
            border: none;
        }
        button.primary:hover {
            background-color: #2980b9;
        }
        #board {
            width: 400px;
            max-width: 85vw;
            box-shadow: 0 4px 15px rgba(0,0,0,0.15);
            border-radius: 4px;
            overflow: hidden;
        }
        #status {
            margin-top: 15px;
            font-size: 1.1rem;
            font-weight: 600;
            color: #34495e;
            user-select: none;
            text-align: center;
        }
    </style>
</head>
<body>

    <div class="container">
        <h1>Schach gegen KI</h1>
        
        <div class="controls-row">
            <div class="control-group">
                <label for="rating-select">Bot-Stärke</label>
                <select id="rating-select">
                    <option value="600">Einsteiger (ca. 600 Elo)</option>
                    <option value="800">Hobby-Spieler (ca. 800 Elo)</option>
                    <option value="1000">Erfahren (ca. 1000 Elo)</option>
                    <option value="1200" selected>Fortgeschritten (ca. 1200 Elo)</option>
                    <option value="1600">Herausfordernd (ca. 1600 Elo)</option>
                    <option value="2000">Experte (ca. 2000 Elo)</option>
                    <option value="2200">Meister (ca. 2200 Elo)</option>
                </select>
            </div>

            <div class="control-group">
                <label for="color-select">Deine Farbe</label>
                <select id="color-select">
                    <option value="w" selected>Weiß</option>
                    <option value="b">Schwarz</option>
                </select>
            </div>
        </div>

        <div class="controls-row">
            <button id="btn-reset" class="primary">Neues Spiel</button>
            <button id="btn-undo">Zug zurück</button>
        </div>

        <div id="board"></div>
        <div id="status">Du bist dran (Weiß)</div>
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.js"></script>

    <script>
        $(document).ready(function() {
            const game = new Chess();
            const $status = $('#status');
            let playerColor = 'w';

            const pieceValues = { p: 10, n: 30, b: 30, r: 50, q: 90, k: 900 };

            function onDragStart (source, piece, position, orientation) {
                if (game.game_over()) return false;
                
                if ((playerColor === 'w' && piece.search(/^b/) !== -1) ||
                    (playerColor === 'b' && piece.search(/^w/) !== -1)) {
                    return false;
                }
                
                if ((game.turn() === 'w' && playerColor === 'b') || 
                    (game.turn() === 'b' && playerColor === 'w')) {
                    return false;
                }
                
                return true; 
            }

            function evaluateBoard() {
                let value = 0;
                const boardState = game.board();
                const botColor = playerColor === 'w' ? 'b' : 'w';

                for (let r = 0; r < 8; r++) {
                    for (let c = 0; c < 8; c++) {
                        const piece = boardState[r][c];
                        if (piece) {
                            const pValue = pieceValues[piece.type];
                            if (piece.color === botColor) {
                                value += pValue;
                            } else {
                                value -= pValue;
                            }
                        }
                    }
                }
                return value;
            }

            function evaluateMove(move) {
                game.move(move);
                let value = evaluateBoard();
                game.undo();
                return value;
            }

            function minimaxDepth2() {
                const possibleMoves = game.moves({ verbose: true });
                let bestMoves = [];
                let bestValue = -Infinity;

                for (let i = 0; i < possibleMoves.length; i++) {
                    const move = possibleMoves[i];
                    game.move(move);

                    if (game.in_checkmate()) {
                        game.undo();
                        return move;
                    }

                    const opponentMoves = game.moves({ verbose: true });
                    let worstValueForBot = Infinity;

                    if (opponentMoves.length === 0) {
                        worstValueForBot = 0;
                    } else {
                        for (let j = 0; j < opponentMoves.length; j++) {
                            game.move(opponentMoves[j]);
                            const boardValue = evaluateBoard();
                            if (boardValue < worstValueForBot) {
                                worstValueForBot = boardValue;
                            }
                            game.undo();
                        }
                    }

                    game.undo();

                    if (worstValueForBot > bestValue) {
                        bestValue = worstValueForBot;
                        bestMoves = [move];
                    } else if (worstValueForBot === bestValue) {
                        bestMoves.push(move);
                    }
                }

                const randomIdx = Math.floor(Math.random() * bestMoves.length);
                return bestMoves[randomIdx];
            }

            function makeBotMove () {
                if (game.game_over()) return;

                const possibleMoves = game.moves({ verbose: true });
                if (possibleMoves.length === 0) return;

                const selectedRating = $('#rating-select').val();
                let chosenMove = null;

                if (selectedRating === "600") {
                    const randomIdx = Math.floor(Math.random() * possibleMoves.length);
                    chosenMove = possibleMoves[randomIdx];
                } 
                else if (selectedRating === "800") {
                    let worstMoves = [];
                    let worstValue = Infinity;
                    for (let i = 0; i < possibleMoves.length; i++) {
                        const moveValue = evaluateMove(possibleMoves[i]);
                        if (moveValue < worstValue) {
                            worstValue = moveValue;
                            worstMoves = [possibleMoves[i]];
                        } else if (moveValue === worstValue) {
                            worstMoves.push(possibleMoves[i]);
                        }
                    }
                    if (Math.random() < 0.25) {
                        const randomIdx = Math.floor(Math.random() * worstMoves.length);
                        chosenMove = worstMoves[randomIdx];
                    } else {
                        const randomIdx = Math.floor(Math.random() * possibleMoves.length);
                        chosenMove = possibleMoves[randomIdx];
                    }
                }
                else if (selectedRating === "1000") {
                    const captures = possibleMoves.filter(m => m.captured);
                    if (captures.length > 0 && Math.random() < 0.5) {
                        const randomIdx = Math.floor(Math.random() * captures.length);
                        chosenMove = captures[randomIdx];
                    } else {
                        const randomIdx = Math.floor(Math.random() * possibleMoves.length);
                        chosenMove = possibleMoves[randomIdx];
                    }
                }
                else if (selectedRating === "1200") {
                    const captures = possibleMoves.filter(m => m.captured);
                    if (captures.length > 0) {
                        const randomIdx = Math.floor(Math.random() * captures.length);
                        chosenMove = captures[randomIdx];
                    } else {
                        const randomIdx = Math.floor(Math.random() * possibleMoves.length);
                        chosenMove = possibleMoves[randomIdx];
                    }
                } 
                else if (selectedRating === "1600") {
                    let bestMoves = [];
                    let bestValue = -Infinity;
                    for (let i = 0; i < possibleMoves.length; i++) {
                        const moveValue = evaluateMove(possibleMoves[i]);
                        if (moveValue > bestValue) {
                            bestValue = moveValue;
                            bestMoves = [possibleMoves[i]]; 
                        } else if (moveValue === bestValue) {
                            bestMoves.push(possibleMoves[i]); 
                        }
                    }
                    const randomIdx = Math.floor(Math.random() * bestMoves.length);
                    chosenMove = bestMoves[randomIdx];
                }
                else if (selectedRating === "2000") {
                    if (Math.random() < 0.15) {
                        const randomIdx = Math.floor(Math.random() * possibleMoves.length);
                        chosenMove = possibleMoves[randomIdx];
                    } else {
                        chosenMove = minimaxDepth2();
                    }
                }
                else if (selectedRating === "2200") {
                    chosenMove = minimaxDepth2();
                }

                if (chosenMove) {
                    game.move(chosenMove);
                    board.position(game.fen());
                    updateStatus();
                }
            }

            function onDrop (source, target) {
                const move = game.move({
                    from: source,
                    to: target,
                    promotion: 'q' 
                });

                if (move === null) return 'snapback';

                updateStatus();

                if (!game.game_over()) {
                    window.setTimeout(makeBotMove, 250);
                }
            }

            function onSnapEnd () {
                board.position(game.fen());
            }

            function updateStatus () {
                let status = '';
                let moveColor = game.turn() === 'w' ? 'Weiß' : 'Schwarz';

                if (game.turn() === playerColor) {
                    status = `Du bist dran (${moveColor})`;
                } else {
                    status = `Bot überlegt (${moveColor})...`;
                }

                if (game.in_checkmate()) {
                    status = 'Spiel vorbei! ' + (game.turn() === playerColor ? 'Der Bot hat gewonnen!' : 'Du hast gewonnen!');
                } else if (game.in_draw()) {
                    status = 'Spiel vorbei! Unentschieden.';
                } else {
                    if (game.in_check()) {
                        status += ' - Schach!';
                    }
                }
                $status.html(status);
            }

            function resetGame() {
                game.reset();
                playerColor = $('#color-select').val();
                
                board.orientation(playerColor === 'w' ? 'white' : 'black');
                board.start();
                
                updateStatus();

                if (playerColor === 'b') {
                    window.setTimeout(makeBotMove, 500);
                }
            }

            // Event-Listener
            $('#btn-reset').on('click', resetGame);
            
            $('#btn-undo').on('click', function() {
                if (game.history().length >= 2) {
                    game.undo();
                    game.undo();
                    board.position(game.fen());
                    updateStatus();
                } else if (game.history().length === 1 && playerColor === 'b') {
                    game.undo();
                    board.position(game.fen());
                    updateStatus();
                    window.setTimeout(makeBotMove, 500);
                }
            });

            $('#color-select').on('change', resetGame);

            const config = {
                draggable: true,
                position: 'start',
                onDragStart: onDragStart,
                onDrop: onDrop,
                onSnapEnd: onSnapEnd,
                pieceTheme: 'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png'
            };

            // Hier wird das Brett direkt erzeugt und sichtbar gemacht
            const board = Chessboard('board', config);
            updateStatus();
        });
    </script>
</body>
</html>

Game Source: Mein Schachbot Deluxe

Creator: BlazeKoala99

Libraries: none

Complexity: complex (404 lines, 14.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: mein-schachbot-deluxe-blazekoala99" to link back to the original. Then publish at arcadelab.ai/publish.