const squareSize = 50;
let currentPlayer = "w";
let isGameOver = false;
let waitingForMove = false; // To prevent duplicate moves
let maxMoves = 50; // Maximum number of moves
let moveCount = 0;
let isSimulationOn = true; // Start simulation automatically
const aiWhite = "https://chess-stockfish-16-api.p.rapidapi.com/chess/api";
const aiBlack = "https://chess-move-maker.p.rapidapi.com/chess";
document.write(`
<head>
<title>Chess AI Tournament</title>
<script type="module">
import { Chess } from "https://cdn.skypack.dev/chess.js";
window.chess = new Chess();
</script>
</head>
<body>
<button id="pauseBtn">Pause</button>
<!-- Container for the canvas -->
<div id="sketch"></div>
</body>
`);
function setup() {
createCanvas(8 * squareSize, 8 * squareSize);
console.log("Simulation started automatically on setup");
runSimulation(); // Automatically start the simulation
}
function draw() {
background(220);
drawBoard();
drawPieces();
}
function drawBoard() {
for (let x = 0; x < 8; x++) {
for (let y = 0; y < 8; y++) {
fill((x + y) % 2 === 0 ? 215 : 100); // White and black squares
rect(x * squareSize, y * squareSize, squareSize, squareSize);
}
}
}
function drawPieces() {
const board = chess.board();
textSize(squareSize * 0.8);
textAlign(CENTER, CENTER);
const pieceSymbols = {
p: "♟", n: "♞", b: "♝", r: "♜", q: "♛", k: "♚", // Black pieces
P: "♙", N: "♘", B: "♗", R: "♖", Q: "♕", K: "♔" // White pieces
};
for (let y = 0; y < 8; y++) {
for (let x = 0; x < 8; x++) {
const piece = board[y][x];
if (piece) {
const symbol = pieceSymbols[piece.color === "w" ? piece.type.toUpperCase() : piece.type];
fill(piece.color === "w" ? 255 : 0);
text(
symbol,
x * squareSize + squareSize / 2,
y * squareSize + squareSize / 2
);
}
}
}
}
async function runSimulation() {
while (isSimulationOn && !isGameOver) {
if (!waitingForMove) {
waitingForMove = true; // Lock moves until current move is processed
await playTurn(); // Execute a move
}
await new Promise(r => setTimeout(r, 500)); // Add delay between moves
}
}
async function playTurn() {
const endpoint = currentPlayer === "w" ? aiWhite : aiBlack;
const fen = chess.fen();
try {
const move = await getMove(fen, endpoint);
if (!chess.move(move)) {
throw new Error(`Invalid move from API: ${JSON.stringify(move)}`);
}
console.log(`Move ${moveCount}: ${currentPlayer} played from ${move.from} to ${move.to}`);
moveCount++;
if (moveCount >= maxMoves) {
evaluateMaterialWinner();
return;
}
if (chess.isGameOver()) {
evaluateWinner();
return;
}
currentPlayer = currentPlayer === "w" ? "b" : "w"; // Switch player
} catch (error) {
console.log("Error during API call:", error);
} finally {
waitingForMove = false; // Unlock for next move
}
}
async function getMove(fen, url) {
if (url === aiWhite) {
return stockfishJS(fen);
} else {
return chessmovemakerJS(fen);
}
}
async function chessmovemakerJS(fen) {
const url = "https://chess-move-maker.p.rapidapi.com/chess";
function fenToBoard(fen) {
const pieceMap = {
'p': 'bP', 'r': 'bR', 'n': 'bN', 'b': 'bB', 'q': 'bQ', 'k': 'bK',
'P': 'wP', 'R': 'wR', 'N': 'wN', 'B': 'wB', 'Q': 'wQ', 'K': 'wK',
};
const rows = fen.split(' ')[0].split('/');
return rows.map(row => {
const expandedRow = [];
for (const char of row) {
if (isNaN(char)) {
expandedRow.push(pieceMap[char] || '');
} else {
expandedRow.push(...Array(parseInt(char)).fill(''));
}
}
return expandedRow;
});
}
const options = {
method: "POST",
headers: {
"x-rapidapi-key": "a4fef1ee6fmshb40f31ccdbfdd52p19565bjsn14ca66e0e06f",
"x-rapidapi-host": "chess-move-maker.p.rapidapi.com",
"Content-Type": "application/json",
},
body: JSON.stringify({
color: currentPlayer === "w" ? "WHITE" : "BLACK",
positions: fenToBoard(fen),
}),
};
const response = await fetch(url, options);
const moves = await response.json();
if (moves.length > 0) {
const { from, to } = moves[0];
return { from, to };
} else {
throw new Error("No moves returned by the API");
}
}
async function stockfishJS(fen) {
const url = "https://chess-stockfish-16-api.p.rapidapi.com/chess/api";
const data = new FormData();
const apiKey = "b6afcf768dmsh065db0d82936420p13e2f4jsn04b3f64caa77";
data.append("fen", fen);
const options = {
method: "POST",
headers: {
"x-rapidapi-key": apiKey,
"x-rapidapi-host": "chess-stockfish-16-api.p.rapidapi.com",
},
body: data,
};
const response = await fetch(url, options);
const dataBack = await response.json();
const bestMove = dataBack.bestmove;
const from = bestMove.slice(0, 2);
const to = bestMove.slice(2, 4);
return { from, to };
}
function evaluateWinner() {
isGameOver = true;
if (chess.isCheckmate()) {
const winner = currentPlayer === "w" ? "Black" : "White";
console.log(`Game over: ${winner} wins by checkmate`);
} else if (chess.isDraw()) {
console.log("Game over: Draw");
} else {
console.log("Game over: Strange condition");
}
console.log("PGN:", chess.pgn());
}
function evaluateMaterialWinner() {
isGameOver = true;
console.log("Game Over - Reached maximum number of moves");
const board = chess.board();
const material = { w: 0, b: 0 };
const values = { p: 1, n: 3, b: 4, r: 5, q: 9, k: 0 };
board.forEach(row => {
row.forEach(piece => {
if (piece) {
material[piece.color] += values[piece.type];
}
});
});
console.log(`Material: White ${material.w}, Black ${material.b}`);
if (material.w > material.b) {
console.log("White wins");
} else if (material.w < material.b) {
console.log("Black wins");
} else {
console.log("Draw!");
}
console.log("PGN:", chess.pgn());
}
document.getElementById("pauseBtn").addEventListener("click", () => {
if (isSimulationOn) {
isSimulationOn = false;
console.log("Simulation paused");
}
});