// Cloned by Killian Daly on 25 May 2024 from World "One Cube World (P5)" by Starter user
// Please leave this clone trail here.
const cw = 600;
const ch = 600;
let playerTurn = true;
let chess = null;
let selectedSquare = null;
const tileSize = cw / 8;
$.getScript("uploads/dalyk34/chess-min.js", function () {
chess = new Chess(); // Initialise chess.js
});
function setup() {
chess = new Chess();
chess.load(chess.fen().replace(/ [KQkq]+ /, " - ")); // Disable castling
createCanvas(cw, ch);
background("lightpink");
drawChessboard();
drawPieces();
}
function endPlayerTurn() {
playerTurn = false;
console.log("Player turn finished. Making AI move...");
makeAIMove();
}
function updatePiecesFromChess() {
const board = chess.board();
pieces = board.map((row) =>
row.map((square) => (square ? square.type.toUpperCase() : " "))
);
}
function redrawBoard() {
background("lightpink");
drawChessboard();
drawPieces();
}
// Utility function to convert row and column to chess notation
function getChessNotation(row, col) {
const colLetters = ["a", "b", "c", "d", "e", "f", "g", "h"];
return colLetters[col] + (8 - row);
}
// Draw the chessboard
function drawChessboard() {
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
// Alternate colours for tiles
fill((row + col) % 2 === 0 ? 240 : 181, (row + col) % 2 === 0 ? 217 : 136, 181);
noStroke();
rect(col * tileSize, row * tileSize, tileSize, tileSize);
}
}
}
// Draw the pieces based on the FEN string
function drawPieces() {
if (!chess) return;
const board = chess.board(); // Get the current board from chess.js
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const piece = board[row][col];
if (piece) {
fill(piece.color === "w" ? "white" : "black");
textAlign(CENTER, CENTER);
textSize(tileSize * 0.6);
text(piece.type.toUpperCase(), col * tileSize + tileSize / 2, row * tileSize + tileSize / 2);
}
}
}
}
function mousePressed() {
checkGameState();
if (!playerTurn) {
return;
}
const col = Math.floor(mouseX / tileSize);
const row = Math.floor(mouseY / tileSize);
if (row >= 0 && row < 8 && col >= 0 && col < 8 && chess) {
const square = getChessNotation(row, col); // Convert mouse click to chess notation
if (selectedSquare) {
// If there's already a selected square, try to make a move
handleCellClick(row, col); // Use handleCellClick to make the move
} else {
// If no square is selected, select the piece on the clicked square
const piece = chess.get(square);
if (piece) {
selectedSquare = square; // Set the selected square to chess notation
console.log(`Selected ${piece.type} at ${square}`);
}
}
// Redraw the board and pieces
redrawBoard();
}
}
function handleCellClick(row, col) {
const from = selectedSquare; // This will already be in chess notation
const to = getChessNotation(row, col); // Convert to chess notation
let move = { from, to };
// Check for pawn promotion
const piece = chess.get(from);
if (piece && piece.type === "p" && (to[1] === "1" || to[1] === "8")) {
const promotionPiece = prompt("Promote pawn to (q/r/b/n):", "q"); // Default to queen
move.promotion = promotionPiece ? promotionPiece.toLowerCase() : "q";
}
const result = chess.move(move); // Attempt the move using chess.js
if (result) {
updatePiecesFromChess(); // Update pieces after valid move
redrawBoard(); // Redraw the board
selectedSquare = null; // Reset the selected square
if (checkGameState()) return; // Stop if the game is over
endPlayerTurn(); // Pass the turn to AI
} else {
console.log("Invalid move!");
selectedSquare = null; // Reset the selection if move is invalid
}
}
async function makeAIMove() {
checkGameState();
const form = new FormData();
form.append("fen", chess.fen()); // Get the current board position in FEN format
const settings = {
async: true,
crossDomain: true,
url: "https://chess-stockfish-16-api.p.rapidapi.com/chess/api",
method: "POST",
headers: {
"x-rapidapi-key": "291a0dfb38mshf850128e2ea20d3p1a81cejsn8348250cd9d2", // API key
"x-rapidapi-host": "chess-stockfish-16-api.p.rapidapi.com",
},
processData: false,
contentType: false,
mimeType: "multipart/form-data",
data: form,
};
$.ajax(settings).done(function (response) {
console.log(response);
const data = JSON.parse(response);
if (data.result === "bestmove (none)" && data.message === "There is no available moves from this position") {
console.log("AI wins! No moves available for the opponent.");
setup();
}
const bestMove = data.bestmove;
if (bestMove) {
const from = bestMove.slice(0, 2); // Extract 'from' square
const to = bestMove.slice(2, 4); // Extract 'to' square
const move = { from, to };
// Handle pawn promotion for AI
const piece = chess.get(from); // Get the piece being moved
if (piece && piece.type === "p" && (to[1] === "1" || to[1] === "8")) {
move.promotion = "q"; // Promote to queen
}
const result = chess.move(move); // Attempt the move using chess.js
if (result) {
updatePiecesFromChess(); // Update board state
redrawBoard(); // Redraw the board
selectedSquare = null; // Reset selection
}
}
});
playerTurn = true;
}
function checkGameState() {
if (chess.in_checkmate()) {
const winner = chess.turn() === "w" ? "Black" : "White";
console.log(`Checkmate! ${winner} wins.`);
return true; // Game over
} else if (chess.in_stalemate()) {
console.log("Stalemate! It's a draw.");
return true; // Game over
} else if (chess.in_draw()) {
console.log("Draw! The game is a tie.");
return true; // Game over
}
return false; // Game continues
}