Mein Schachbot Deluxe
by BlazeKoala99404 lines14.6 KB
<!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.