Code viewer for World: Deep Flannel
// 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
}