// ==UserScript==
// @name Chess.com Bot/Cheat (by Admin0)
// @namespace Admin0
// @version 1.1.0
// @description Chess.com Bot/Cheat that finds the best move!
// @author Admin0
// @license Chess.com Bot/Cheat © 2024 by Admin0, © 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
// @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/9.0.0/stockfish.js
// @require https://greasyfork.org/scripts/445697/code/index.js
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @run-at document-start
// ==/UserScript==
// CLEAN REWRITE - CHESS.COM THEMED VERSION 3.0
const currentVersion = '3.0';
function main() {
// Core variables setup
var stockfishObjectURL;
var engine = document.engine = {};
var myVars = document.myVars = {};
myVars.autoMove = GM_getValue('autoMove', false); // Load saved autoMove
myVars.suggestMove = GM_getValue('suggestMove', false); // Load saved suggestMove
myVars.autoMatch = GM_getValue('autoMatch', false); // Load saved autoMatch
myVars.customDepth = GM_getValue('customDepth', 11); // Load saved depth, default to 11
myVars.bestMoveHighlightColor = GM_getValue('bestMoveHighlightColor', '#7fa650'); // Chess.com green
var myFunctions = document.myFunctions = {};
var lastValue = GM_getValue('customDepth', 11); // Also initialize lastValue with saved/default depth
// Core chess engine logic from Script3 (the working one)
myFunctions.color = function(dat) {
console.log("[Move] Processing:", dat);
console.log("[Highlight] Attempting highlight on board element:", board ? board.nodeName : 'Board not found!'); // Diagnostic log
let response = dat;
let res1 = response.substring(0, 2); // From square
let res2 = response.substring(2, 4); // To square
// Execute move if auto-move is enabled
if (myVars.autoMove === true) {
myFunctions.movePiece(res1, res2);
}
// Reset thinking state
isThinking = false;
// Convert chess notation to Chess.com's grid system
res1 = res1.replace(/^a/, "1")
.replace(/^b/, "2")
.replace(/^c/, "3")
.replace(/^d/, "4")
.replace(/^e/, "5")
.replace(/^f/, "6")
.replace(/^g/, "7")
.replace(/^h/, "8");
res2 = res2.replace(/^a/, "1")
.replace(/^b/, "2")
.replace(/^c/, "3")
.replace(/^d/, "4")
.replace(/^e/, "5")
.replace(/^f/, "6")
.replace(/^g/, "7")
.replace(/^h/, "8");
// Highlight destination square
$(board.nodeName)
.prepend('<div class="highlight square-' + res2 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0.7;" data-test-element="highlight"></div>')
.children(':first')
.delay(1800)
.queue(function() {
$(this).remove();
});
// Highlight origin square
$(board.nodeName)
.prepend('<div class="highlight square-' + res1 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0.7;" data-test-element="highlight"></div>')
.children(':first')
.delay(1800)
.queue(function() {
$(this).remove();
});
};
// Move execution function from Script3
myFunctions.movePiece = function(from, to) {
console.log("[Move] Executing move from", from, "to", to);
try {
// Get legal moves from the game
let legalMoves = board.game.getLegalMoves();
// Find our move in legal moves
for (let each = 0; each < legalMoves.length; each++) {
if (legalMoves[each].from === from && legalMoves[each].to === to) {
let move = legalMoves[each];
// Check for promotion (pawn to last rank)
let promotion = undefined;
let piece = board.game.getPiece(from);
if (piece && piece.type === 'p' && (to[1] === '8' || to[1] === '1')) {
promotion = 'q'; // Default promote to queen
console.log("[Move] Promoting pawn to queen");
}
// Execute the move
board.game.move({
from: move.from,
to: move.to,
promotion: promotion,
animate: false,
userGenerated: true
});
console.log("[Move] Executed successfully");
return;
}
}
console.warn("[Move] No legal move found:", from, to);
} catch (error) {
console.error("[Move] Error executing move:", error);
}
};
// Parser from Script3
function parser(e) {
console.log("[Engine] Message:", e.data);
if (e.data.includes('bestmove')) {
console.log("[Engine] Found best move:", e.data);
myFunctions.color(e.data.split(' ')[1]);
isThinking = false;
}
}
// Engine load function from Script3
myFunctions.loadChessEngine = function() {
console.log("[Engine] Loading Stockfish...");
try {
if (!stockfishObjectURL) {
stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
}
engine.engine = new Worker(stockfishObjectURL);
engine.engine.onmessage = e => {
parser(e);
};
engine.engine.onerror = e => {
console.error("[Engine] Error:", e);
isThinking = false;
};
engine.engine.postMessage('ucinewgame');
console.log("[Engine] Loaded successfully");
} catch (error) {
console.error("[Engine] Load failed:", error);
}
};
// Engine reload function
myFunctions.reloadChessEngine = function() {
console.log("[Engine] Reloading...");
try {
if (engine.engine) {
engine.engine.terminate();
}
isThinking = false;
stockfishObjectURL = null; // Force recreation
setTimeout(() => {
myFunctions.loadChessEngine();
console.log("[Engine] Reloaded successfully");
}, 100);
} catch (error) {
console.error("[Engine] Reload failed:", error);
}
};
// Run engine at specified depth
myFunctions.runChessEngine = function(depth) {
console.log("[Engine] Running at depth", depth);
let fen = board.game.getFEN();
console.log("[Engine] Position:", fen);
engine.engine.postMessage(`position fen ${fen}`);
isThinking = true;
engine.engine.postMessage(`go depth ${depth}`);
lastValue = depth;
};
// Auto run function
myFunctions.autoRun = function(depth) {
if (board.game.getTurn() == board.game.getPlayingAs()) {
myFunctions.runChessEngine(depth || myVars.customDepth);
}
};
// Function to handle delayed auto-run
function other(delay) {
let endTime = Date.now() + delay;
let timer = setInterval(() => {
if (Date.now() >= endTime) {
myFunctions.autoRun(myVars.customDepth);
canGo = true;
clearInterval(timer);
}
}, 10);
}
// Auto start new game
myFunctions.startNewGame = function() {
console.log("[Match] Starting new game...");
// Find New Game button in different places
const modalNewGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
if (modalNewGameButton.length) {
modalNewGameButton[0].click();
console.log("[Match] Clicked New Game from modal");
myVars.hasAutoMatched = true;
myVars.gameEnded = false;
return;
}
const newGameButton = $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
if (newGameButton.length) {
newGameButton[0].click();
console.log("[Match] Clicked New Game button");
myVars.hasAutoMatched = true;
myVars.gameEnded = false;
return;
}
console.log("[Match] No New Game button found");
};
// Function to handle spinner visibility
myFunctions.spinner = function() {
if (loaded && $('#overlay').length) {
$('#overlay').css('display', isThinking ? 'block' : 'none');
}
};
// Handle keyboard shortcuts
document.onkeydown = function(e) {
const depthKeys = {
81: 1, 87: 2, 69: 3, 82: 4, 84: 5, 89: 6, 85: 7, 73: 8, 79: 9, 80: 10,
65: 11, 83: 12, 68: 13, 70: 14, 71: 15, 72: 16, 74: 17, 75: 18, 76: 19,
90: 20, 88: 21, 67: 22, 86: 23, 66: 24, 78: 25, 77: 26, 187: 100
};
if (depthKeys[e.keyCode]) {
myVars.customDepth = depthKeys[e.keyCode];
if (loaded) {
$('#depthValue').text(myVars.customDepth);
}
GM_setValue('customDepth', myVars.customDepth); // Save the new depth
location.reload(); // Reload the page
}
// Toggle UI with ESC
if (e.keyCode === 27 && loaded) {
$('#chessBot').toggle();
}
};
// UI Creation function - CHESS.COM THEMED
var loaded = false;
myFunctions.loadEx = function() {
if (loaded) return;
try {
console.log("[UI] Creating Chess.com themed interface...");
board = $('chess-board')[0] || $('wc-chess-board')[0];
if (!board) {
console.warn("[UI] Board not found yet");
return;
}
myVars.board = board;
// Create main container with Chess.com styling
const panel = document.createElement('div');
panel.id = 'chessBot';
panel.style = `
position: fixed;
right: 20px;
top: 50%;
transform: translateY(-50%);
width: 280px;
background-color: #312e2b;
color: #bababa;
font-family: "Segoe UI", Arial, sans-serif;
z-index: 9999;
padding: 15px;
border-radius: 5px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
font-size: 14px;
`;
// Create header
const header = document.createElement('div');
header.style = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
border-bottom: 1px solid #464442;
padding-bottom: 10px;
`;
const title = document.createElement('h2');
title.innerText = 'Chess.com Bot';
title.style = `
margin: 0;
font-size: 18px;
font-weight: 600;
color: #bababa;
`;
const version = document.createElement('span');
version.innerText = 'v3.0';
version.style = `
font-size: 12px;
opacity: 0.8;
color: #bababa;
`;
header.appendChild(title);
header.appendChild(version);
panel.appendChild(header);
// Create spinner overlay
const overlay = document.createElement('div');
overlay.id = 'overlay';
overlay.style = `
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(49, 46, 43, 0.85);
z-index: 10000;
display: none;
border-radius: 5px;
`;
const spinner = document.createElement('div');
spinner.style = `
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin-top: -20px;
margin-left: -20px;
border: 3px solid #bababa;
border-top-color: #7fa650;
border-radius: 50%;
animation: spin 1s infinite linear;
`;
const spinStyle = document.createElement('style');
spinStyle.textContent = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`;
document.head.appendChild(spinStyle);
overlay.appendChild(spinner);
panel.appendChild(overlay);
// Create content sections
const createSection = (title) => {
const section = document.createElement('div');
section.style = `
margin-bottom: 15px;
`;
const sectionTitle = document.createElement('h3');
sectionTitle.innerText = title;
sectionTitle.style = `
margin: 0 0 10px 0;
font-size: 16px;
color: #bababa;
border-bottom: 1px solid #464442;
padding-bottom: 5px;
`;
section.appendChild(sectionTitle);
return section;
};
// Create depth section
const depthSection = createSection('Engine Depth');
const depthDisplay = document.createElement('div');
depthDisplay.style = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
background-color: #3a3634;
padding: 8px 12px;
border-radius: 4px;
`;
const depthLabel = document.createElement('span');
depthLabel.innerText = 'Current Depth:';
const depthValue = document.createElement('span');
depthValue.id = 'depthValue';
depthValue.innerText = myVars.customDepth;
depthValue.style = `
font-weight: bold;
color: #7fa650;
`;
depthDisplay.appendChild(depthLabel);
depthDisplay.appendChild(depthValue);
const depthInfo = document.createElement('p');
depthInfo.innerText = 'Press A-Z keys to change depth (Q=1, W=2, etc.)';
depthInfo.style = `
margin: 5px 0;
font-size: 12px;
opacity: 0.7;
`;
const depthInput = document.createElement('div');
depthInput.style = `
display: flex;
align-items: center;
margin-top: 10px;
`;
const depthInputLabel = document.createElement('label');
depthInputLabel.innerText = 'Set Depth:';
depthInputLabel.style = 'margin-right: 10px;';
const depthInputField = document.createElement('input');
depthInputField.type = 'number';
depthInputField.id = 'customDepthInput';
depthInputField.min = '1';
depthInputField.max = '100';
depthInputField.value = myVars.customDepth;
depthInputField.style = `
background-color: #3a3634;
border: 1px solid #464442;
color: #bababa;
padding: 5px;
border-radius: 3px;
width: 60px;
`;
depthInputField.addEventListener('change', function() {
const value = parseInt(this.value);
if (!isNaN(value) && value >= 1 && value <= 100) {
myVars.customDepth = value;
depthValue.innerText = value;
GM_setValue('customDepth', myVars.customDepth); // Save the new depth
location.reload(); // Reload the page
} else {
this.value = GM_getValue('customDepth', 11); // Reset to saved value if input is invalid
}
});
depthInput.appendChild(depthInputLabel);
depthInput.appendChild(depthInputField);
depthSection.appendChild(depthDisplay);
depthSection.appendChild(depthInfo);
depthSection.appendChild(depthInput);
panel.appendChild(depthSection);
// Create game options section
const optionsSection = createSection('Game Options');
const createCheckbox = (id, label) => {
const container = document.createElement('div');
container.style = `
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = id;
checkbox.style = `
margin-right: 10px;
cursor: pointer;
`;
const checkLabel = document.createElement('label');
checkLabel.htmlFor = id;
checkLabel.innerText = label;
checkLabel.style = 'cursor: pointer;';
container.appendChild(checkbox);
container.appendChild(checkLabel);
return container;
};
const autoRunCheck = createCheckbox('suggestMove', 'Enable Suggested Move');
const autoMoveCheck = createCheckbox('autoMove', 'Enable auto move');
const autoMatchCheck = createCheckbox('autoMatch', 'Enable auto match');
optionsSection.appendChild(autoRunCheck);
optionsSection.appendChild(autoMoveCheck);
optionsSection.appendChild(autoMatchCheck);
panel.appendChild(optionsSection);
// Set initial state from loaded vars
autoRunCheck.querySelector('input').checked = myVars.suggestMove;
autoMoveCheck.querySelector('input').checked = myVars.autoMove;
autoMatchCheck.querySelector('input').checked = myVars.autoMatch;
// Create delay section
const delaySection = createSection('Suggestion Delay');
const createDelayInput = (id, label, defaultValue) => {
const container = document.createElement('div');
container.style = `
display: flex;
align-items: center;
margin-bottom: 10px;
`;
const inputLabel = document.createElement('label');
inputLabel.htmlFor = id;
inputLabel.innerText = label;
inputLabel.style = `
flex: 1;
`;
const input = document.createElement('input');
input.type = 'number';
input.id = id;
input.min = '0.1';
input.step = '0.1';
input.value = defaultValue;
input.style = `
background-color: #3a3634;
border: 1px solid #464442;
color: #bababa;
padding: 5px;
border-radius: 3px;
width: 60px;
`;
container.appendChild(inputLabel);
container.appendChild(input);
return container;
};
const minDelayInput = createDelayInput('timeDelayMin', 'Min Delay (s):', '0.1');
const maxDelayInput = createDelayInput('timeDelayMax', 'Max Delay (s):', '1.0');
delaySection.appendChild(minDelayInput);
delaySection.appendChild(maxDelayInput);
panel.appendChild(delaySection);
// Create display section
const displaySection = createSection('Display');
const colorContainer = document.createElement('div');
colorContainer.style = `
display: flex;
align-items: center;
`;
const colorLabel = document.createElement('label');
colorLabel.htmlFor = 'highlightColorInput';
colorLabel.innerText = 'Highlight Color:';
colorLabel.style = 'flex: 1;';
const colorInput = document.createElement('input');
colorInput.type = 'color';
colorInput.id = 'highlightColorInput';
colorInput.value = myVars.bestMoveHighlightColor;
colorInput.style = `
width: 60px;
height: 30px;
padding: 0;
border: none;
background: none;
`;
colorInput.addEventListener('change', function() {
myVars.bestMoveHighlightColor = this.value;
GM_setValue('bestMoveHighlightColor', this.value);
});
colorContainer.appendChild(colorLabel);
colorContainer.appendChild(colorInput);
displaySection.appendChild(colorContainer);
panel.appendChild(displaySection);
// Create buttons section
const actionsSection = createSection('Actions');
const createButton = (text, onClick, primary = false) => {
const button = document.createElement('button');
button.innerText = text;
button.addEventListener('click', onClick);
button.style = `
background-color: ${primary ? '#7fa650' : '#5d5955'};
color: #fff;
border: none;
padding: 10px;
margin-bottom: 10px;
border-radius: 3px;
width: 100%;
cursor: pointer;
font-weight: ${primary ? 'bold' : 'normal'};
transition: background-color 0.2s;
`;
button.addEventListener('mouseover', function() {
this.style.backgroundColor = primary ? '#8fb761' : '#6e6a66';
});
button.addEventListener('mouseout', function() {
this.style.backgroundColor = primary ? '#7fa650' : '#5d5955';
});
return button;
};
const reloadButton = createButton('Reload Chess Engine', () => myFunctions.reloadChessEngine(), true);
const issueButton = createButton('Report an Issue', () => {
window.open('https://greasyfork.org/en/scripts/534105-chess-com-bot-cheat-by-admin0/feedback', '_blank');
});
const updateButton = createButton('Check for Updates', () => {
window.open('https://greasyfork.org/en/scripts/534105-chess-com-bot-cheat-by-admin0', '_blank');
});
actionsSection.appendChild(reloadButton);
actionsSection.appendChild(issueButton);
actionsSection.appendChild(updateButton);
panel.appendChild(actionsSection);
// Add drag handle
const dragHandle = document.createElement('div');
dragHandle.style = `
position: absolute;
top: 0;
left: 0;
right: 0;
height: 15px;
cursor: move;
background-color: rgba(255, 255, 255, 0.05);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
`;
// Make panel draggable
let isDragging = false;
let offsetX, offsetY;
dragHandle.addEventListener('mousedown', function(e) {
isDragging = true;
offsetX = e.clientX - panel.getBoundingClientRect().left;
offsetY = e.clientY - panel.getBoundingClientRect().top;
});
document.addEventListener('mousemove', function(e) {
if (isDragging) {
panel.style.right = 'auto';
panel.style.top = (e.clientY - offsetY) + 'px';
panel.style.left = (e.clientX - offsetX) + 'px';
panel.style.transform = 'none';
}
});
document.addEventListener('mouseup', function() {
isDragging = false;
});
panel.appendChild(dragHandle);
// Add footer
const footer = document.createElement('div');
footer.style = `
margin-top: 15px;
padding-top: 10px;
border-top: 1px solid #464442;
font-size: 12px;
text-align: center;
opacity: 0.7;
`;
footer.innerText = 'Press ESC to toggle interface';
panel.appendChild(footer);
// Append panel to body
document.body.appendChild(panel);
loaded = true;
console.log("[UI] Chess.com themed interface created successfully");
} catch (error) {
console.error("[UI] Error creating interface:", error);
}
};
// Main interval loop
const waitForChessBoard = setInterval(() => {
if (loaded) {
board = $('chess-board')[0] || $('wc-chess-board')[0];
// Read checkbox states directly from DOM
try {
myVars.suggestMove = document.getElementById('suggestMove').checked;
myVars.autoMove = document.getElementById('autoMove').checked;
myVars.autoMatch = document.getElementById('autoMatch').checked;
// Save the current state
GM_setValue('suggestMove', myVars.suggestMove);
GM_setValue('autoMove', myVars.autoMove);
GM_setValue('autoMatch', myVars.autoMatch);
// Read delay values
let minDelay = parseFloat(document.getElementById('timeDelayMin').value) || 0.1;
let maxDelay = parseFloat(document.getElementById('timeDelayMax').value) || 1.0;
myVars.delay = Math.random() * (maxDelay - minDelay) + minDelay;
} catch (e) {
console.warn("[UI] Error reading UI state:", e);
}
// Update spinner
myVars.isThinking = isThinking;
myFunctions.spinner();
// Check for game over
const gameOverModal = $('.game-over-modal-content');
if (gameOverModal.length > 0 && !myVars.gameEnded) {
console.log("[Game] Game over detected");
myVars.gameEnded = true;
myVars.hasAutoMatched = false;
}
// Check turn
try {
if (!myVars.gameEnded && board && board.game) {
myTurn = (board.game.getTurn() == board.game.getPlayingAs());
} else {
myTurn = false;
}
} catch (e) {
myTurn = false;
}
// Log state (for debugging)
console.log(`[State] SuggestMove:${myVars.suggestMove} AutoMove:${myVars.autoMove} AutoMatch:${myVars.autoMatch} MyTurn:${myTurn} Thinking:${isThinking} CanGo:${canGo}`);
// Make sure engine is loaded
if (!engine.engine) {
myFunctions.loadChessEngine();
}
// Auto Run Logic (Now Suggested Move Logic)
if (myVars.suggestMove && canGo && !isThinking && myTurn && !myVars.gameEnded) {
console.log("[Auto] Triggering suggested move analysis...");
canGo = false;
const currentDelay = myVars.delay * 1000;
other(currentDelay);
}
// Auto Match Logic
if (myVars.autoMatch && myVars.gameEnded && !myVars.hasAutoMatched) {
console.log("[Auto] Triggering auto match...");
myFunctions.startNewGame();
}
} else if ($('chess-board, wc-chess-board').length > 0) {
// Try to load UI if not loaded yet
myFunctions.loadEx();
}
}, 100);
}
// Global variables
var isThinking = false;
var canGo = true;
var myTurn = false;
var board;
// Start the script
window.addEventListener("load", (event) => {
console.log("[Script] Chess.com Bot v3.0 starting...");
main();
});