// ==UserScript== // @name Chess.com Stockfish Bot // @namespace BottleOrg Scripts // @version 1.7.5 // @description Simplifies move logic to reliably play the first move as White without user interaction. // @author [REDACTED] - Rightful Owner(qbaonguyen050@gmail.com, Gemini 2.5 Pro, Kimi K2 // @license Chess.com Bot/Cheat by BottleOrg(qbaonguyen050@gmail.com) // @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 https://update.greasyfork.icu/scripts/526240/Chesscom%20Stockfish%20Bot.user.js // @updateURL https://update.greasyfork.icu/scripts/526240/Chesscom%20Stockfish%20Bot.meta.js // ==/UserScript== const currentVersion = '1.7.5'; const scriptURL = 'https://greasyfork.org/en/scripts/526240-chess-com-stockfish-bot'; function checkForUpdate() { console.log("Checking for script updates..."); GM_xmlhttpRequest({ method: "GET", url: scriptURL, onload: function(response) { if (response.status === 200) { const html = response.responseText; const versionMatch = html.match(/@version\s+([\d.]+)/); if (versionMatch && versionMatch[1]) { const latestVersion = versionMatch[1]; console.log("Latest version found:", latestVersion); if (compareVersions(latestVersion, currentVersion) > 0) { const message = `New Version: ${latestVersion} has been uploaded. Would you like me to take you there or continue with old version ${currentVersion}? (Not recommended for stability)`; if (confirm(message)) { window.location.href = scriptURL; } else { console.log("User chose to continue with old version."); } } else { console.log("No newer version available."); } } } }, }); } function compareVersions(v1, v2) { const parts1 = v1.split('.').map(Number); const parts2 = v2.split('.').map(Number); for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { const p1 = parts1[i] || 0; const p2 = parts2[i] || 0; if (p1 > p2) return 1; if (p1 < p2) return -1; } return 0; } function main() { let myVars = document.myVars = { autoMove: false, autoRun: false, autoMatch: false, delay: 0.1, gameEnded: false }; let myFunctions = document.myFunctions = {}; const stockfishAPI_URI = "https://stockfish.online/api/s/v2.php"; let board; myFunctions.rescan = function() { if (board && board.game && typeof board.game.getFEN === 'function') { const fen = board.game.getFEN(); console.log("Using built-in FEN:", fen); return fen; } console.warn("Could not get FEN from board.game object."); return null; }; myFunctions.color = function(dat) { const bestmoveUCI = dat.split(' ')[1]; console.log("Extracted bestmove UCI:", bestmoveUCI); if (myVars.autoMove) myFunctions.movePiece(bestmoveUCI); else myFunctions.highlightMove(bestmoveUCI); isThinking = false; myFunctions.spinner(); }; myFunctions.highlightMove = function(bestmoveUCI) { const res1 = bestmoveUCI.substring(0, 2); const res2 = bestmoveUCI.substring(2, 4); $(board).prepend(`
`).delay(1800).queue(function() { $(this).remove(); }); $(board).prepend(``).delay(1800).queue(function() { $(this).remove(); }); }; myFunctions.movePiece = function(bestmoveUCI) { if (!board || !board.game) { console.error("Board or board.game not initialized!"); return; } const fromSquare = bestmoveUCI.substring(0, 2); const toSquare = bestmoveUCI.substring(2, 4); const promotionPiece = bestmoveUCI.length > 4 ? bestmoveUCI.substring(4, 5) : null; const legalMoves = board.game.getLegalMoves(); const foundMove = legalMoves.find(move => move.from === fromSquare && move.to === toSquare && (promotionPiece ? move.promotion === promotionPiece : !move.promotion) ); if (foundMove) { console.log("Executing move:", bestmoveUCI); board.game.move({ ...foundMove, animate: true, userGenerated: true }); } else { console.warn(`Could not find a legal move for UCI: ${bestmoveUCI}.`); } }; myFunctions.fetchBestMoveFromAPI = function(fen, depth) { const apiURL = `${stockfishAPI_URI}?fen=${encodeURIComponent(fen)}&depth=${depth}`; console.log(`Fetching from: ${apiURL}`); GM_xmlhttpRequest({ method: "GET", url: apiURL, onload: function(response) { if (response.status === 200) { try { const jsonResponse = JSON.parse(response.responseText); if (jsonResponse.success) myFunctions.color(jsonResponse.bestmove); else { console.error("API failed:", jsonResponse); isThinking = false; myFunctions.spinner(); } } catch (e) { console.error("API parse error:", e); isThinking = false; myFunctions.spinner(); } } else { console.error("API error:", response.status); isThinking = false; myFunctions.spinner(); } }, onerror: function() { console.error("API request error"); isThinking = false; myFunctions.spinner(); } }); }; myFunctions.startNewGame = function() { console.log("Starting new game..."); const newGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])') || $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])'); if (newGameButton.length) { newGameButton[0].click(); } else { console.error("Could not find a 'New Game' button."); } }; myFunctions.declineRematch = function() { const declineButton = $('.cc-button-component.cc-button-secondary[aria-label="Decline"], .cc-button-component.cc-button-secondary:contains("Decline")'); if (declineButton.length) { declineButton[0].click(); console.log("Declined rematch."); } }; let lastValue = 12, MAX_DEPTH = 15, MIN_DEPTH = 1; myFunctions.runChessEngine = function(depth) { depth = Math.max(MIN_DEPTH, Math.min(MAX_DEPTH, depth)); const fen = myFunctions.rescan(); if (!fen) { console.log("Skipping analysis, FEN not available."); return; } console.log(`Analyzing FEN: ${fen}, Depth: ${depth}`); isThinking = true; myFunctions.spinner(); myFunctions.fetchBestMoveFromAPI(fen, depth); lastValue = depth; updateDepthDisplay(); }; function updateDepthDisplay() { if (uiElementsLoaded && $('#depthText')[0]) { $('#depthText')[0].innerHTML = `Depth: ${lastValue}`; } } myFunctions.incrementDepth = function(delta) { lastValue = Math.max(MIN_DEPTH, Math.min(MAX_DEPTH, lastValue + delta)); updateDepthDisplay(); }; myFunctions.autoRun = function() { if (board && board.game && board.game.getTurn() === board.game.getPlayingAs()) { myFunctions.runChessEngine(lastValue); } }; document.onkeydown = function(e) { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') 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 187: myFunctions.incrementDepth(1); break; case 189: myFunctions.incrementDepth(-1); break; } }; myFunctions.spinner = function() { if (uiElementsLoaded && $('#overlay')[0]) { $('#overlay')[0].style.display = isThinking ? 'block' : 'none'; } }; let uiElementsLoaded = false; let loaded = false; myFunctions.loadEx = function() { try { console.log("Attempting to load UI..."); board = document.querySelector('chess-board, wc-chess-board'); const style = document.createElement('style'); style.innerHTML = ` .chess-ui-panel { width: 280px; background: linear-gradient(135deg, #ffe6e6, #fff5f5); border: 2px solid #ffcccc; border-radius: 12px; box-shadow: 4px 4px 16px rgba(0,0,0,0.3); animation: fadeIn 1s ease-out; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; user-select: none; } .chess-ui-header { background: #ffcccc; border-bottom: 1px solid #ffb3b3; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: 8px; cursor: move; font-weight: bold; color: #800000; text-align: center; } .chess-ui-body { padding: 10px; } .chess-ui-panel button { background: #e91e63; border: none; color: white; padding: 8px 12px; margin: 4px 2px; border-radius: 5px; cursor: pointer; transition: box-shadow 0.3s ease, transform 0.2s ease; } .chess-ui-panel button:hover { box-shadow: 0 0 8px #ff69b4; transform: scale(1.05); } .chess-ui-panel input[type="checkbox"], .chess-ui-panel input[type="number"] { margin: 5px 0; padding: 4px; border: 1px solid #ffcccc; border-radius: 4px; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } body.is-dragging { user-select: none; } `; document.head.appendChild(style); const panel = document.createElement('div'); panel.className = "chess-ui-panel"; panel.style.cssText = 'position: fixed; top: 10px; right: 10px; z-index: 10000;'; panel.innerHTML = `Depth: ${lastValue}
Keys: Q-G (1-15), +/-
Engine: Stockfish API 😘