// ==UserScript== // @name Chess.com Bot/Cheat - Stockfish API Debug 3 - Ad Removed - FIXED - COMPLETE SCRIPT // @namespace BottleOrg Scripts // @version 1.6.2-DEBUG - Stockfish API Debug 3 - No Ads - FIXED - COMPLETE SCRIPT - IMPROVED MOVE HANDLING // @description Chess.com Bot/Cheat using Stockfish Online API. Ad Removed. - FIXED loadEx and UI update errors - DEBUGGING VERSION 3 - IMPROVED MOVE HANDLING - COMPLETE SCRIPT // @author MrAuzzie (Original), Modified by BottleOrg && Gemini 2.0 to become better. // @license Chess.com Bot/Cheat © 2023 by MrAuzzie#998142, © All Rights Reserved // @match https://www.chess.com/play/* // @match https://www.chess.com/game/* // @match https://www.chess.com/puzzles/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_getResourceText // @grant GM_registerMenuCommand // @require https://greasyfork.org/scripts/445697/code/index.js // @require https://code.jquery.com/jquery-3.6.0.min.js // @run-at document-start // @downloadURL none // ==/UserScript== // Changelogs // Made this Debug V3 script into official script due to it is working correctly // Working Stockfish V16+ using their API // Debugging V2 script Found out engine is not responding due to not finding a legal move // Debugging V1 script engine responded but did not move // Using stockfish V10.0.2 as it is working // Removed CDN stockfish V16 engines and engine fallbacks because it doesn't work // Added engine fallbacks if an engine fails // added error handling and alerts // Upgraded from Stockfish V9 to Stockfish V10.0.2 // Using Stockfish 9 currently const currentVersion = '1.6.2-OFFICIAL'; function main() { var engine = document.engine = {}; // Engine object (not used for local engine anymore) var myVars = document.myVars = {}; myVars.autoMovePiece = false; myVars.autoRun = false; myVars.delay = 0.1; var myFunctions = document.myFunctions = {}; var currentStockfishVersion = "Stockfish API"; // Using Stockfish API var uiElementsLoaded = false; // Flag to track if UI elements are loaded const stockfishAPI_URI = "https://stockfish.online/api/s/v2.php"; // Stockfish API URI stop_b = stop_w = 0; s_br = s_br2 = s_wr = s_wr2 = 0; obs = ""; myFunctions.rescan = function(lev) { var ari = $("chess-board") .find(".piece") .map(function() { return this.className; }) .get(); jack = ari.map(f => f.substring(f.indexOf(' ') + 1)); function removeWord(arr, word) { for (var i = 0; i < arr.length; i++) { arr[i] = arr[i].replace(word, ''); } } removeWord(ari, 'square-'); jack = ari.map(f => f.substring(f.indexOf(' ') + 1)); for (var i = 0; i < jack.length; i++) { jack[i] = jack[i].replace('br', 'r') .replace('bn', 'n') .replace('bb', 'b') .replace('bq', 'q') .replace('bk', 'k') .replace('bb', 'b') .replace('bn', 'n') .replace('br', 'r') .replace('bp', 'p') .replace('wp', 'P') .replace('wr', 'R') .replace('wn', 'N') .replace('wb', 'B') .replace('br', 'R') .replace('wn', 'N') .replace('wb', 'B') .replace('wq', 'Q') .replace('wk', 'K') .replace('wb', 'B') } str2 = ""; var count = 0, str = ""; for (var j = 8; j > 0; j--) { for (var i = 1; i < 9; i++) { (str = (jack.find(el => el.includes([i] + [j])))) ? str = str.replace(/[^a-zA-Z]+/g, ''): str = ""; if (str == "") { count++; str = count.toString(); if (!isNaN(str2.charAt(str2.length - 1))) str2 = str2.slice(0, -1); else { count = 1; str = count.toString() } } str2 += str; if (i == 8) { count = 0; str2 += "/"; } } } str2 = str2.slice(0, -1); //str2=str2+" KQkq - 0" color = ""; wk = wq = bk = bq = "0"; const move = $('vertical-move-list') .children(); if (move.length < 2) { stop_b = stop_w = s_br = s_br2 = s_wr = s_wr2 = 0; } if (stop_b != 1) { if (move.find(".black.node:contains('K')") .length) { bk = ""; bq = ""; stop_b = 1; console.log('debug secb'); } } else { bq = ""; bk = ""; } if (stop_b != 1)(bk = (move.find(".black.node:contains('O-O'):not(:contains('O-O-O'))") .length) ? "" : "k") ? (bq = (move.find(".black.node:contains('O-O-O')") .length) ? bk = "" : "q") : bq = ""; if (s_br != 1) { if (move.find(".black.node:contains('R')") .text() .match('[abcd]+')) { bq = ""; s_br = 1 } } else bq = ""; if (s_br2 != 1) { if (move.find(".black.node:contains('R')") .text() .match('[hgf]+')) { bk = ""; s_br2 = 1 } } else bk = ""; if (stop_b == 0) { if (s_br == 0) if (move.find(".white.node:contains('xa8')") .length > 0) { bq = ""; s_br = 1; console.log('debug b castle_r'); } if (s_br2 == 0) if (move.find(".white.node:contains('xh8')") .length > 0) { bk = ""; s_br2 = 1; console.log('debug b castle_l'); } } if (stop_w != 1) { if (move.find(".white.node:contains('K')") .length) { wk = ""; wq = ""; stop_w = 1; console.log('debug secw'); } } else { wq = ""; wk = ""; } if (stop_w != 1)(wk = (move.find(".white.node:contains('O-O'):not(:contains('O-O-O'))") .length) ? "" : "K") ? (wq = (move.find(".white.node:contains('O-O-O')") .length) ? wk = "" : "Q") : wq = ""; if (s_wr != 1) { if (move.find(".white.node:contains('R')") .text() .match('[abcd]+')) { wq = ""; s_wr = 1 } } else wq = ""; if (s_wr2 != 1) { if (move.find(".white.node:contains('R')") .text() .match('[hgf]+')) { wk = ""; s_wr2 = 1 } } else wk = ""; if (stop_w == 0) { if (s_wr == 0) if (move.find(".black.node:contains('xa1')") .length > 0) { wq = ""; s_wr = 1; console.log('debug w castle_l'); } if (s_wr2 == 0) if (move.find(".black.node:contains('xh1')") .length > 0) { wk = ""; s_wr2 = 1; console.log('debug w castle_r'); } } if ($('.coordinates') .children() .first() .text() == 1) { str2 = str2 + " b " + wk + wq + bk + bq; color = "white"; } else { str2 = str2 + " w " + wk + wq + bk + bq; color = "black"; } //console.log(str2); return str2; } myFunctions.color = function(dat){ console.log("myFunctions.color CALLED with dat:", dat); // Added logging at start response = dat; const bestmoveUCI = response.split(' ')[1]; // Extract UCI move directly (e.g., "e2e4") console.log("Extracted bestmove UCI from API response:", bestmoveUCI); if(myVars.autoMove == true){ console.log("Auto-move is enabled, calling movePiece with UCI move:", bestmoveUCI); // Log before movePiece myFunctions.movePiece(bestmoveUCI); // Pass UCI move directly to movePiece } else { console.log("Auto-move is disabled, only highlighting UCI move:", bestmoveUCI); // Log if auto-move off myFunctions.highlightMove(bestmoveUCI); // Call highlight function with UCI move } isThinking = false; console.log("myFunctions.color COMPLETED"); // Log at the end of color } myFunctions.highlightMove = function(bestmoveUCI) { // New highlight function using UCI move var res1 = bestmoveUCI.substring(0, 2); var res2 = bestmoveUCI.substring(2, 4); $(board.nodeName) .prepend('
') .children(':first') .delay(1800) .queue(function() { $(this) .remove(); }); $(board.nodeName) .prepend('') .children(':first') .delay(1800) .queue(function() { $(this) .remove(); }); console.log("myFunctions.highlightMove COMPLETED - move highlighted:", bestmoveUCI); } myFunctions.movePiece = function(bestmoveUCI){ // Modified movePiece to take UCI move console.log("myFunctions.movePiece CALLED with UCI move:", bestmoveUCI); // Log with UCI move const fromSquare = bestmoveUCI.substring(0, 2); const toSquare = bestmoveUCI.substring(2, 4); console.log("Parsed fromSquare:", fromSquare, "toSquare:", toSquare); const legalMoves = board.game.getLegalMoves(); let foundMove = null; for (const move of legalMoves) { if (move.from === fromSquare && move.to === toSquare) { foundMove = move; break; } } if (foundMove) { console.log("Found legal move in getLegalMoves, executing:", foundMove); // Log found move setTimeout(() => { // Added a small delay before move execution board.game.move({ ...foundMove, promotion: 'false', animate: false, userGenerated: true }); console.log("myFunctions.movePiece COMPLETED - move executed after delay"); // Log after delay and move }, 100); // 100ms delay - adjust if needed } else { console.warn("myFunctions.movePiece - LEGAL MOVE NOT FOUND in getLegalMoves for UCI move:", bestmoveUCI); // Warn with UCI move } } myFunctions.reloadChessEngine = function() { console.log(`Reloading the chess engine (Stockfish API - no reload needed).`); alert("Reloading engine for Stockfish API is not needed. Re-analyzing will use the API again."); } myFunctions.loadChessEngine = function() { console.log(`Using Stockfish Online API. No local engine loading.`); if (uiElementsLoaded) { $('#engineVersionText')[0].innerHTML = "Chess Engine: Stockfish API Loaded"; } } myFunctions.fetchBestMoveFromAPI = function(fen, depth) { const apiURL = `${stockfishAPI_URI}?fen=${encodeURIComponent(fen)}&depth=${depth}`; console.log(`Fetching best move from API: ${apiURL}`); GM_xmlhttpRequest({ method: "GET", url: apiURL, onload: function(response) { if (response.status === 200) { try { const jsonResponse = JSON.parse(response.responseText); if (jsonResponse.success === true) { const bestmove = jsonResponse.bestmove; console.log(`API Response SUCCESS: Bestmove - ${bestmove}, Evaluation - ${jsonResponse.evaluation}, Mate - ${jsonResponse.mate}`); // Success log console.log("Calling myFunctions.color with bestmove:", bestmove); // Log before calling color myFunctions.color(bestmove); } else { console.error("API request was successful, but 'success' is false in response:", jsonResponse); alert("Stockfish API returned an error. Please check console for details."); isThinking = false; // Stop thinking state if (uiElementsLoaded) { $('#engineVersionText')[0].innerHTML = "Chess Engine: Stockfish API Error"; } } } catch (e) { console.error("Error parsing API response JSON:", e); alert("Error parsing Stockfish API response. Please check console for details."); isThinking = false; // Stop thinking state if (uiElementsLoaded) { $('#engineVersionText')[0].innerHTML = "Chess Engine: API Response Error"; } } } else { console.error("Stockfish API request failed with status:", response.status, response.statusText); alert(`Stockfish API request failed. Status: ${response.status} ${response.statusText}. Please check console and internet connection.`); isThinking = false; // Stop thinking state if (uiElementsLoaded) { $('#engineVersionText')[0].innerHTML = "Chess Engine: API Request Failed"; } } }, onerror: function(error) { console.error("GM_xmlhttpRequest error:", error); alert("Error making Stockfish API request. Please check console and internet connection."); isThinking = false; // Stop thinking state if (uiElementsLoaded) { $('#engineVersionText')[0].innerHTML = "Chess Engine: API Request Error"; } } }); }; var lastValue = 11; myFunctions.runChessEngine = function(depth){ if (currentStockfishVersion === "Failed" || currentStockfishVersion === "None") { console.warn("Chess engine is not available (failed to load). Cannot run engine."); return; } var fen = board.game.getFEN(); console.log(`[Stockfish API] Requesting analysis for FEN: ${fen}, Depth: ${depth}`); isThinking = true; myFunctions.fetchBestMoveFromAPI(fen, 7); // Call API function with REDUCED DEPTH (7) for bullet lastValue = depth; // Keep lastValue for UI display, but API uses fixed depth 7 now for testing } myFunctions.autoRun = function(lstValue){ if (currentStockfishVersion === "Failed" || currentStockfishVersion === "None") return; if(board.game.getTurn() == board.game.getPlayingAs()){ myFunctions.runChessEngine(lstValue); } } document.onkeydown = function(e) { if (currentStockfishVersion === "Failed" || currentStockfishVersion === "None") return; switch (e.keyCode) { case 81: myFunctions.runChessEngine(1); break; case 87: myFunctions.runChessEngine(2); break; case 69: myFunctions.runChessEngine(3); break; case 82: myFunctions.runChessEngine(4); break; case 84: myFunctions.runChessEngine(5); break; case 89: myFunctions.runChessEngine(6); break; case 85: myFunctions.runChessEngine(7); break; case 73: myFunctions.runChessEngine(8); break; case 79: myFunctions.runChessEngine(9); break; case 80: myFunctions.runChessEngine(10); break; case 65: myFunctions.runChessEngine(11); break; case 83: myFunctions.runChessEngine(12); break; case 68: myFunctions.runChessEngine(13); break; case 70: myFunctions.runChessEngine(14); break; case 71: myFunctions.runChessEngine(15); break; case 72: myFunctions.runChessEngine(16); break; case 74: myFunctions.runChessEngine(17); break; case 75: myFunctions.runChessEngine(18); case 76: myFunctions.runChessEngine(19); break; case 90: myFunctions.runChessEngine(20); break; case 88: myFunctions.runChessEngine(21); break; case 67: myFunctions.runChessEngine(22); break; case 86: myFunctions.runChessEngine(23); break; case 66: myFunctions.runChessEngine(24); break; case 78: myFunctions.runChessEngine(25); break; case 77: myFunctions.runChessEngine(26); break; case 187: myFunctions.runChessEngine(100); break; } }; myFunctions.spinner = function() { if(isThinking == true){ $('#overlay')[0].style.display = 'block'; } if(isThinking == false) { $('#overlay')[0].style.display = 'none'; } } let dynamicStyles = null; function addAnimation(body) { if (!dynamicStyles) { dynamicStyles = document.createElement('style'); dynamicStyles.type = 'text/css'; document.head.appendChild(dynamicStyles); } dynamicStyles.sheet.insertRule(body, dynamicStyles.length); } var loaded = false; myFunctions.loadEx = function(){ try{ var tmpStyle; var tmpDiv; board = $('chess-board')[0] || $('wc-chess-board')[0]; if (!board) { // Check if board element is found console.warn("Chessboard element not found yet. Retrying..."); return; // Exit and retry in the next interval } myVars.board = board; var div = document.createElement('div') var content = `Your Current Depth Is: 11
Press a key on your keyboard to change this!
Chess Engine: Stockfish API