// ==UserScript== // additional copyright/license info: //© All Rights Reserved // //Chess.com Enhanced Experience © 2024 by Akashdeep // // ==UserScript // @name Chess.com UltraX bot with Panel // @namespace Akashdeep // @version 1.0.0.5 // @description Enhances your Chess.com experience with move suggestions, UI enhancements, and customizable features. Credits to GoodtimeswithEno for the initial move highlighting and basic chess engine implementation. // @author Akashdeep // @license Chess.com Enhanced Experience © 2024 by Akashdeep, © All Rights Reserved // @match https://www.chess.com/play/* // @match https://www.chess.com/game/* // @match https://www.chess.com/puzzles/* // @match https://www.chess.com/* // @icon data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @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/10.0.2/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 // @liscense MIT // @downloadURL // @updateURL // @downloadURL none // ==/UserScript== //Don't touch anything below unless you know what your doing! const currentVersion = '1.0.0.5'; // Sets the current version function main() { var stockfishObjectURL; var engine = document.engine = {}; var myVars = document.myVars = {}; myVars.autoMovePiece = false; myVars.autoRun = false; myVars.delay = 0.1; var myFunctions = document.myFunctions = {}; myVars.playStyle = { aggressive: Math.random() * 0.5 + 0.3, // 0.3-0.8 tendency for aggressive moves defensive: Math.random() * 0.5 + 0.3, // 0.3-0.8 tendency for defensive moves tactical: Math.random() * 0.6 + 0.2, // 0.2-0.8 tendency for tactical moves positional: Math.random() * 0.6 + 0.2 // 0.2-0.8 tendency for positional moves }; myVars.preferredOpenings = [ "e4", "d4", "c4", "Nf3" // Just examples, could be expanded ].sort(() => Math.random() - 0.5); // Randomize the order myVars.playerFingerprint = GM_getValue('playerFingerprint', { favoredPieces: Math.random() < 0.5 ? 'knights' : 'bishops', openingTempo: Math.random() * 0.5 + 0.5, // 0.5-1.0 opening move speed tacticalAwareness: Math.random() * 0.4 + 0.6, // 0.6-1.0 tactical vision exchangeThreshold: Math.random() * 0.3 + 0.1, // When to accept exchanges attackingStyle: ['kingside', 'queenside', 'central'][Math.floor(Math.random() * 3)] }); // Save on first run if (!GM_getValue('playerFingerprint')) { GM_setValue('playerFingerprint', myVars.playerFingerprint); } // Add to myVars initialization myVars.tacticalProfile = GM_getValue('tacticalProfile', { strengths: [ getRandomTacticalStrength(), getRandomTacticalStrength() ], weaknesses: [ getRandomTacticalWeakness(), getRandomTacticalWeakness() ] }); // Save on first run if (!GM_getValue('tacticalProfile')) { GM_setValue('tacticalProfile', myVars.tacticalProfile); } function getRandomTacticalStrength() { const strengths = [ 'fork', 'pin', 'skewer', 'discovery', 'zwischenzug', 'removing-defender', 'attraction' ]; return strengths[Math.floor(Math.random() * strengths.length)]; } function getRandomTacticalWeakness() { const weaknesses = [ 'long-calculation', 'quiet-moves', 'backward-moves', 'zugzwang', 'prophylaxis', 'piece-coordination' ]; return weaknesses[Math.floor(Math.random() * weaknesses.length)]; } 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){ response = dat; var res1 = response.substring(0, 2); var res2 = response.substring(2, 4); // Check if automove is enabled and make the move if(myVars.autoMove === true){ console.log(`Auto move enabled, moving from ${res1} to ${res2}`); myFunctions.movePiece(res1, res2); } else { console.log(`Auto move disabled, highlighting ${res1} to ${res2}`); } isThinking = false; 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"); // Use custom highlight color if available const highlightColor = myVars.highlightColor || 'rgb(235, 97, 80)'; $(board.nodeName) .prepend(`
`) .children(':first') .delay(1800) .queue(function() { $(this) .remove(); }); $(board.nodeName) .prepend(`
`) .children(':first') .delay(1800) .queue(function() { $(this) .remove(); }); } myFunctions.movePiece = function(from, to) { // Check if the move is legal before attempting to make it let isLegalMove = false; let moveObject = null; for (let each = 0; each < board.game.getLegalMoves().length; each++) { if (board.game.getLegalMoves()[each].from === from && board.game.getLegalMoves()[each].to === to) { isLegalMove = true; moveObject = board.game.getLegalMoves()[each]; break; } } if (!isLegalMove) { console.log(`Attempted illegal move: ${from} to ${to}`); return; } // Add a small delay before making the move to simulate human reaction time setTimeout(() => { try { // Make the actual move board.game.move({ ...moveObject, promotion: moveObject.promotion || 'q', // Default to queen for simplicity animate: true, userGenerated: true }); console.log(`Successfully moved from ${from} to ${to}`); } catch (error) { console.error("Error making move:", error); } }, 100 + Math.random() * 300); // Small random delay to appear more human-like } // Replace simple movement simulation with this more advanced version function simulateNaturalMouseMovement(from, to, callback) { // Convert chess coordinates to screen positions const fromPos = getSquarePosition(from); const toPos = getSquarePosition(to); // Create a bezier curve path with a slight variance const controlPoint1 = { x: fromPos.x + (toPos.x - fromPos.x) * 0.3 + (Math.random() * 40 - 20), y: fromPos.y + (toPos.y - fromPos.y) * 0.1 + (Math.random() * 40 - 20) }; const controlPoint2 = { x: fromPos.x + (toPos.x - fromPos.x) * 0.7 + (Math.random() * 40 - 20), y: fromPos.y + (toPos.y - fromPos.y) * 0.9 + (Math.random() * 40 - 20) }; // Calculate movement duration based on distance const distance = Math.sqrt(Math.pow(toPos.x - fromPos.x, 2) + Math.pow(toPos.y - fromPos.y, 2)); const baseDuration = 300 + Math.random() * 400; const movementDuration = baseDuration + distance * (0.5 + Math.random() * 0.5); // Create array of points along path const steps = 15 + Math.floor(distance / 30); const points = []; for (let i = 0; i <= steps; i++) { const t = i / steps; points.push(getBezierPoint(t, fromPos, controlPoint1, controlPoint2, toPos)); } // Execute the movement with variable speed executeMouseMovement(points, 0, movementDuration / steps, callback); } // Add these functions for more realistic timing function calculateMoveComplexity(from, to) { // Approximate complexity based on piece type, capture, check, etc. // Returns a value between 0 (simple) and 1 (complex) return Math.random() * 0.7 + 0.3; // Placeholder implementation } function calculateHumanLikeDelay(complexity) { // More complex positions take longer to think about const baseDelay = 500; // Base delay in ms const complexityFactor = 2500; // Max additional delay for complex positions return baseDelay + (complexity * complexityFactor * Math.random()); } function getRandomThinkingDelay() { // Humans don't immediately start calculating return 300 + Math.random() * 700; } function parser(e) { if(e.data.includes('bestmove')) { const bestMove = e.data.split(' ')[1]; // Extract multiple moves from engine analysis if available let alternativeMoves = [bestMove]; try { if (e.data.includes('pv')) { // Try to extract alternative moves from multiPV or previous info lines const lines = e.data.split('\n') .filter(line => line.includes(' pv ')) .map(line => { const pvIndex = line.indexOf(' pv '); return line.substring(pvIndex + 4).split(' ')[0]; }); if (lines.length > 1) { alternativeMoves = lines; } } } catch (error) { console.log("Error extracting alternative moves", error); } // Decide whether to use best move or an alternative let moveToPlay = bestMove; const currentDepth = lastValue; // For higher depths, sometimes choose alternative moves if (currentDepth >= 15 && alternativeMoves.length > 1 && Math.random() < 0.35) { // Select a random move from top 5 (or fewer if not available) const maxIndex = Math.min(5, alternativeMoves.length); const randomIndex = Math.floor(Math.random() * (maxIndex - 1)) + 1; // Skip index 0 (best move) moveToPlay = alternativeMoves[randomIndex] || bestMove; console.log(`Using alternative move ${moveToPlay} instead of best move ${bestMove}`); } else if (Math.random() < getBlunderProbability()) { // Sometimes make a "human-like" suboptimal move moveToPlay = generateHumanLikeMove(bestMove, e.data); console.log(`Using human-like move ${moveToPlay} instead of best move ${bestMove}`); } myFunctions.color(moveToPlay); isThinking = false; } } function getBlunderProbability() { // Use custom blunder rate from slider if available const userBlunderRate = myVars.blunderRate !== undefined ? myVars.blunderRate : 0.05; // Make blunder probability vary based on multiple factors const gamePhase = estimateGamePhase(); const timeRemaining = estimateTimeRemaining(); const complexity = estimatePositionComplexity(); // Base probability comes from user settings let baseProb = userBlunderRate; // More likely to blunder in time pressure if (timeRemaining < 30) { baseProb += 0.1 * (1 - (timeRemaining / 30)); } // More likely to blunder in complex positions if (complexity > 0.6) { baseProb += 0.05 * (complexity - 0.6) * 2; } // More likely to blunder in the endgame when tired if (gamePhase > 30) { baseProb += 0.03 * ((gamePhase - 30) / 10); } // Add randomness to make it unpredictable return Math.min(0.4, baseProb * (0.7 + Math.random() * 0.6)); } function estimateGamePhase() { // Estimate how far the game has progressed (0-40 approx) try { const moveList = $('vertical-move-list').children().length; return moveList / 2; // Rough estimate of move number } catch (e) { return 15; // Default to middle game } } function estimateTimeRemaining() { // Try to get the clock time if available try { const clockEl = document.querySelector('.clock-component'); if (clockEl) { const timeText = clockEl.textContent; if (timeText.includes(':')) { const parts = timeText.split(':'); if (parts.length === 2) { const minutes = parseInt(parts[0]); const seconds = parseInt(parts[1]); return minutes * 60 + seconds; } } else { // Handle single number format (e.g., just seconds) return parseInt(timeText); } } // Try alternative clock selectors const altClockEl = document.querySelector('.clock-time-monospace') || document.querySelector('.clock-time') || document.querySelector('[data-cy="clock-time"]'); if (altClockEl) { const timeText = altClockEl.textContent; if (timeText.includes(':')) { const parts = timeText.split(':'); if (parts.length === 2) { const minutes = parseInt(parts[0]); const seconds = parseInt(parts[1]); return minutes * 60 + seconds; } } else { return parseInt(timeText); } } } catch (e) { console.log("Error getting time remaining:", e); } // Default value if clock can't be read return 180; // 3 minutes as default } function estimatePositionComplexity() { // Calculate a complexity score between 0-1 // This would ideally analyze the position for tactical elements return Math.random() * 0.8 + 0.2; // Placeholder } function generateHumanLikeMove(bestMove, engineData) { // Significantly enhance the human-like behavior // Sometimes choose 2nd, 3rd, or even 4th best moves if (engineData.includes('pv') && Math.random() < 0.4) { try { // Extract multiple lines from engine analysis const lines = engineData.split('\n') .filter(line => line.includes(' pv ')) .map(line => { const pvIndex = line.indexOf(' pv '); return line.substring(pvIndex + 4).split(' ')[0]; }); if (lines.length > 1) { // Weight moves by their quality (prefer better moves, but sometimes choose worse ones) const moveIndex = Math.floor(Math.pow(Math.random(), 2.5) * Math.min(lines.length, 4)); return lines[moveIndex] || bestMove; } } catch (e) { console.log("Error extracting alternative moves", e); } } // Occasionally make a typical human error based on common patterns if (Math.random() < 0.15) { // Approximate a plausible human move (e.g., moving to adjacent square) const fromSquare = bestMove.substring(0, 2); const toSquare = bestMove.substring(2, 4); // Simple adjustment - occasionally play a shorter move (undershoot) if (Math.random() < 0.7) { const files = "abcdefgh"; const ranks = "12345678"; const fromFile = fromSquare.charAt(0); const fromRank = fromSquare.charAt(1); const toFile = toSquare.charAt(0); const toRank = toSquare.charAt(1); // Calculate direction const fileDiff = files.indexOf(toFile) - files.indexOf(fromFile); const rankDiff = ranks.indexOf(toRank) - ranks.indexOf(fromRank); // Sometimes undershoot by one square if (Math.abs(fileDiff) > 1 || Math.abs(rankDiff) > 1) { const newToFile = files[files.indexOf(fromFile) + (fileDiff > 0 ? Math.max(1, fileDiff-1) : Math.min(-1, fileDiff+1))]; const newToRank = ranks[ranks.indexOf(fromRank) + (rankDiff > 0 ? Math.max(1, rankDiff-1) : Math.min(-1, rankDiff+1))]; // Check if the new square is valid if (newToFile && newToRank) { const alternativeMove = fromSquare + newToFile + newToRank; // Verify this is a legal move before returning for (let each=0; each { parser(e); }; engine.engine.onerror = e => { console.log("Worker Error: "+e); }; engine.engine.postMessage('ucinewgame'); } console.log('loaded chess engine'); } var lastValue = 11; myFunctions.runChessEngine = function(depth) { // Get time-adjusted depth var adjustedDepth = getAdjustedDepth(); // Get position type var fen = board.game.getFEN(); var positionType = analyzePositionType(fen); // Log the depth adjustment console.log(`Original depth: ${depth}, Adjusted for time/position: ${adjustedDepth}`); engine.engine.postMessage(`position fen ${fen}`); console.log('updated: ' + `position fen ${fen}`); isThinking = true; // Use multipv for alternative moves when depth is high if (depth >= 15) { engine.engine.postMessage(`setoption name MultiPV value 5`); } else { engine.engine.postMessage(`setoption name MultiPV value 1`); } engine.engine.postMessage(`go depth ${adjustedDepth}`); lastValue = depth; // Keep original depth for UI display } function analyzePositionType(fen) { // Determine position type: opening, middlegame, endgame, tactical const piecesCount = fen.split(' ')[0].match(/[pnbrqkPNBRQK]/g).length; if (piecesCount > 25) return 'opening'; if (piecesCount < 12) return 'endgame'; return 'middlegame'; } function adjustDepthByPosition(requestedDepth, positionType) { // Humans play more accurately in different phases if (positionType === 'opening' && Math.random() < 0.7) { // In openings, humans often play memorized moves return requestedDepth + Math.floor(Math.random() * 3); } else if (positionType === 'endgame' && Math.random() < 0.5) { // In endgames, calculation may be more/less precise return requestedDepth + (Math.random() < 0.5 ? -1 : 1); } // Occasionally randomize depth slightly return Math.max(1, requestedDepth + (Math.random() < 0.3 ? Math.floor(Math.random() * 3) - 1 : 0)); } myFunctions.autoRun = function(lstValue){ if(board.game.getTurn() == board.game.getPlayingAs()){ myFunctions.runChessEngine(lstValue); } } document.onkeydown = function(e) { 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); break; 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){ $('#thinking-indicator').addClass('active'); } if(isThinking == false) { $('#thinking-indicator').removeClass('active'); } } 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]; myVars.board = board; var div = document.createElement('div') var content = `

Panel Pro By @akashdeep

Current Depth: 11

Press a key (Q-Z) to change depth

11

Playing Style Settings

5
5
5
5
2

Advanced Settings

`; div.innerHTML = content; div.setAttribute('id','settingsContainer'); board.parentElement.parentElement.appendChild(div); //Add CSS styles var botStyles = document.createElement('style'); botStyles.innerHTML = ` @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap'); #settingsContainer { background-color: #1e1e2e; color: #cdd6f4; border-radius: 12px; padding: 20px; margin-top: 15px; box-shadow: 0 8px 24px rgba(0,0,0,0.3); font-family: 'Roboto', sans-serif; max-width: 400px; margin-left: auto; margin-right: auto; border: 1px solid #313244; } .chess-bot-container { display: flex; flex-direction: column; gap: 16px; } .bot-header { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 5px; position: relative; } .bot-logo { display: flex; align-items: center; justify-content: center; color: #89b4fa; } .bot-title { margin: 0; color: #89b4fa; font-size: 20px; font-weight: 500; letter-spacing: 0.5px; } .thinking-indicator { position: absolute; right: 0; display: none; align-items: center; } .thinking-indicator.active { display: flex; } .dot { width: 8px; height: 8px; margin: 0 2px; background-color: #89b4fa; border-radius: 50%; opacity: 0.6; } .dot1 { animation: pulse 1.5s infinite; } .dot2 { animation: pulse 1.5s infinite 0.3s; } .dot3 { animation: pulse 1.5s infinite 0.6s; } @keyframes pulse { 0%, 100% { transform: scale(1); opacity: 0.6; } 50% { transform: scale(1.3); opacity: 1; } } .bot-tabs { display: flex; gap: 2px; margin-bottom: -15px; } .tab-button { background-color: #313244; color: #a6adc8; border: none; border-radius: 8px 8px 0 0; padding: 8px 16px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s; flex: 1; text-align: center; } .tab-button:hover { background-color: #45475a; color: #cdd6f4; } .tab-button.active { background-color: #45475a; color: #cdd6f4; } .bot-tabs-content { background-color: #45475a; border-radius: 0 8px 8px 8px; padding: 16px; } .tab-content { display: none; } .tab-content.active { display: block; } .settings-section-title { margin-top: 0; margin-bottom: 12px; color: #89b4fa; font-size: 16px; font-weight: 500; text-align: center; } .bot-info { display: flex; justify-content: center; margin-bottom: 5px; } .depth-card { background-color: #313244; border-radius: 8px; padding: 12px 16px; text-align: center; width: 100%; border: 1px solid #45475a; } .depth-display { font-size: 16px; margin: 0 0 5px 0; font-weight: 400; } .depth-display strong { color: #89b4fa; font-weight: 600; } .key-hint { font-size: 12px; color: #a6adc8; margin: 0; font-weight: 300; } .bot-controls { display: flex; flex-direction: column; gap: 16px; } .control-group { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .control-item { display: flex; flex-direction: column; gap: 6px; } .toggle-container { position: relative; } .toggle-input { opacity: 0; width: 0; height: 0; position: absolute; } .toggle-label { display: flex; align-items: center; gap: 10px; cursor: pointer; } .toggle-button { position: relative; display: inline-block; width: 40px; height: 20px; background-color: #45475a; border-radius: 20px; transition: all 0.3s; } .toggle-button:before { content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%; background-color: #cdd6f4; top: 2px; left: 2px; transition: all 0.3s; } .toggle-input:checked + .toggle-label .toggle-button { background-color: #89b4fa; } .toggle-input:checked + .toggle-label .toggle-button:before { transform: translateX(20px); } .toggle-text { font-size: 14px; } .slider-container { display: flex; flex-direction: column; gap: 6px; } .slider-container label { font-size: 13px; color: #a6adc8; } .number-input { width: 100%; background: #313244; border: 1px solid #45475a; border-radius: 6px; color: #cdd6f4; padding: 8px 10px; font-size: 14px; transition: border-color 0.3s; } .number-input:focus { outline: none; border-color: #89b4fa; } .bot-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 5px; } .action-button { display: flex; align-items: center; justify-content: center; gap: 8px; border: none; border-radius: 8px; padding: 10px 16px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .primary-button { background-color: #89b4fa; color: #1e1e2e; } .primary-button:hover { background-color: #b4befe; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(137, 180, 250, 0.3); } .secondary-button { background-color: #45475a; color: #cdd6f4; } .secondary-button:hover { background-color: #585b70; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(69, 71, 90, 0.3); } .action-button:active { transform: translateY(0); } .depth-control { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; } .depth-control label { font-size: 13px; color: #a6adc8; } .slider-controls { display: flex; align-items: center; gap: 8px; } .depth-slider { flex: 1; height: 6px; -webkit-appearance: none; appearance: none; background: #45475a; border-radius: 3px; outline: none; } .depth-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #89b4fa; cursor: pointer; } .depth-slider::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: #89b4fa; cursor: pointer; } .depth-button { width: 24px; height: 24px; border-radius: 50%; background: #45475a; color: #cdd6f4; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 16px; font-weight: bold; transition: background-color 0.2s; } .depth-button:hover { background: #585b70; } #depthValue { font-size: 14px; font-weight: 500; color: #89b4fa; text-align: center; } `; document.head.appendChild(botStyles); //spinnerContainer var spinCont = document.createElement('div'); spinCont.setAttribute('style','display:none;'); spinCont.setAttribute('id','overlay'); div.prepend(spinCont); //spinner var spinr = document.createElement('div') spinr.setAttribute('style',` margin: 0 auto; height: 40px; width: 40px; animation: rotate 0.8s infinite linear; border: 4px solid #89b4fa; border-right-color: transparent; border-radius: 50%; box-shadow: 0 0 10px rgba(137, 180, 250, 0.4); `); spinCont.appendChild(spinr); addAnimation(`@keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`); $('#depthSlider').on('input', function() { const depth = parseInt($(this).val()); $('#depthValue').text(depth); lastValue = depth; $('#depthText')[0].innerHTML = "Current Depth: " + depth + ""; }); $('#decreaseDepth').on('click', function() { const currentDepth = parseInt($('#depthSlider').val()); if (currentDepth > 1) { const newDepth = currentDepth - 1; $('#depthSlider').val(newDepth).trigger('input'); } }); $('#increaseDepth').on('click', function() { const currentDepth = parseInt($('#depthSlider').val()); if (currentDepth < 26) { const newDepth = currentDepth + 1; $('#depthSlider').val(newDepth).trigger('input'); } }); // Fix tab switching and initialize all controls $(document).on('click', '.tab-button', function() { $('.tab-button').removeClass('active'); $(this).addClass('active'); const tabId = $(this).data('tab'); $('.tab-content').removeClass('active'); $(`#${tabId}`).addClass('active'); }); // Initialize play style sliders with values from myVars if (myVars.playStyle) { $('#aggressiveSlider').val(Math.round(((myVars.playStyle.aggressive - 0.3) / 0.5) * 10)); $('#aggressiveValue').text($('#aggressiveSlider').val()); $('#defensiveSlider').val(Math.round(((myVars.playStyle.defensive - 0.3) / 0.5) * 10)); $('#defensiveValue').text($('#defensiveSlider').val()); $('#tacticalSlider').val(Math.round(((myVars.playStyle.tactical - 0.2) / 0.6) * 10)); $('#tacticalValue').text($('#tacticalSlider').val()); $('#positionalSlider').val(Math.round(((myVars.playStyle.positional - 0.2) / 0.6) * 10)); $('#positionalValue').text($('#positionalSlider').val()); } // Set the blunder rate slider const blunderRate = myVars.blunderRate !== undefined ? Math.round(myVars.blunderRate * 10) : 2; $('#blunderRateSlider').val(blunderRate); $('#blunderRateValue').text(blunderRate); // Setup the style sliders $('.style-slider').on('input', function() { const value = $(this).val(); $(`#${this.id}Value`).text(value); // Update the myVars.playStyle object const styleType = this.id.replace('Slider', ''); if (styleType === 'blunderRate') { myVars.blunderRate = parseFloat(value) / 10; } else if (myVars.playStyle && styleType in myVars.playStyle) { if (styleType === 'aggressive' || styleType === 'defensive') { myVars.playStyle[styleType] = 0.3 + (parseFloat(value) / 10) * 0.5; } else { myVars.playStyle[styleType] = 0.2 + (parseFloat(value) / 10) * 0.6; } } }); // Initialize advanced settings if (myVars.adaptToRating !== undefined) { $('#adaptToRating').prop('checked', myVars.adaptToRating); } if (myVars.useOpeningBook !== undefined) { $('#useOpeningBook').prop('checked', myVars.useOpeningBook); } if (myVars.highlightColor) { $('#highlightColor').val(myVars.highlightColor); } // Set up preferred opening selection if (myVars.preferredOpenings && myVars.preferredOpenings.length === 1) { $('#preferredOpeningSelect').val(myVars.preferredOpenings[0]); } else { $('#preferredOpeningSelect').val('random'); } // Set up advanced settings event handlers $('#adaptToRating').on('change', function() { myVars.adaptToRating = $(this).prop('checked'); }); $('#useOpeningBook').on('change', function() { myVars.useOpeningBook = $(this).prop('checked'); }); $('#highlightColor').on('input', function() { myVars.highlightColor = $(this).val(); }); $('#preferredOpeningSelect').on('change', function() { const selectedOpening = $(this).val(); if (selectedOpening === 'random') { myVars.preferredOpenings = ["e4", "d4", "c4", "Nf3"].sort(() => Math.random() - 0.5); } else { myVars.preferredOpenings = [selectedOpening]; } }); // Setup hotkey options and additional config const extraSettings = `
7
`; $('#advanced-settings .advanced-controls').append(extraSettings); // Initialize additional settings myVars.enableHotkeys = true; myVars.randomizeTiming = true; myVars.mouseMovementRealism = 0.7; // Setup additional event handlers $('#enableHotkeys').on('change', function() { myVars.enableHotkeys = $(this).prop('checked'); }); $('#randomizeTiming').on('change', function() { myVars.randomizeTiming = $(this).prop('checked'); }); $('#mouseMovementSlider').on('input', function() { const value = $(this).val(); $('#mouseMovementSliderValue').text(value); myVars.mouseMovementRealism = parseFloat(value) / 10; }); $('#playingProfileSelect').on('change', function() { const profile = $(this).val(); if (profile !== 'custom') { // Preset profiles with appropriate settings switch(profile) { case 'beginner': $('#depthSlider').val(3).trigger('input'); $('#blunderRateSlider').val(7).trigger('input'); $('#aggressiveSlider').val(Math.floor(3 + Math.random() * 5)).trigger('input'); $('#tacticalSlider').val(3).trigger('input'); break; case 'intermediate': $('#depthSlider').val(6).trigger('input'); $('#blunderRateSlider').val(5).trigger('input'); $('#tacticalSlider').val(5).trigger('input'); break; case 'advanced': $('#depthSlider').val(9).trigger('input'); $('#blunderRateSlider').val(3).trigger('input'); $('#tacticalSlider').val(7).trigger('input'); break; case 'expert': $('#depthSlider').val(12).trigger('input'); $('#blunderRateSlider').val(2).trigger('input'); $('#tacticalSlider').val(8).trigger('input'); $('#positionalSlider').val(8).trigger('input'); break; case 'master': $('#depthSlider').val(15).trigger('input'); $('#blunderRateSlider').val(1).trigger('input'); $('#tacticalSlider').val(9).trigger('input'); $('#positionalSlider').val(9).trigger('input'); break; } } }); // Add CSS for new elements const extraStyles = document.createElement('style'); extraStyles.innerHTML = ` .advanced-section { margin-top: 15px; padding-top: 15px; border-top: 1px solid #313244; } .profile-selection { margin-top: 15px; } .playStyle-controls, .advanced-controls { display: flex; flex-direction: column; gap: 12px; } .style-slider-container { display: flex; align-items: center; gap: 10px; } .style-slider-container label { font-size: 13px; color: #cdd6f4; width: 120px; } .style-slider { flex: 1; height: 6px; -webkit-appearance: none; appearance: none; background: #313244; border-radius: 3px; outline: none; } .style-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; border-radius: 50%; background: #89b4fa; cursor: pointer; } .style-slider-container span { font-size: 14px; font-weight: 500; color: #89b4fa; width: 20px; text-align: center; } .highlight-color-picker { display: flex; align-items: center; gap: 10px; margin-top: 10px; } .highlight-color-picker label { font-size: 13px; color: #cdd6f4; } .color-input { -webkit-appearance: none; width: 30px; height: 30px; border: none; border-radius: 50%; background: none; cursor: pointer; } .color-input::-webkit-color-swatch { border: none; border-radius: 50%; box-shadow: 0 0 0 2px #45475a; } .opening-selection { display: flex; align-items: center; gap: 10px; margin-top: 10px; } .opening-selection label { font-size: 13px; color: #cdd6f4; } .select-input { flex: 1; background: #313244; border: 1px solid #45475a; border-radius: 6px; color: #cdd6f4; padding: 8px 10px; font-size: 14px; transition: border-color 0.3s; } .select-input:focus { outline: none; border-color: #89b4fa; } `; document.head.appendChild(extraStyles); // Load saved settings before applying them to the UI myFunctions.loadSettings(); // Apply loaded settings to UI controls $('#autoRun').prop('checked', myVars.autoRun); $('#autoMove').prop('checked', myVars.autoMove); $('#depthSlider').val(lastValue); $('#depthValue').text(lastValue); $('#depthText').html("Current Depth: " + lastValue + ""); if (myVars.highlightColor) { $('#highlightColor').val(myVars.highlightColor); } // Update the play style sliders with saved values if (myVars.playStyle) { $('#aggressiveSlider').val(Math.round(((myVars.playStyle.aggressive - 0.3) / 0.5) * 10)); $('#aggressiveValue').text($('#aggressiveSlider').val()); $('#defensiveSlider').val(Math.round(((myVars.playStyle.defensive - 0.3) / 0.5) * 10)); $('#defensiveValue').text($('#defensiveSlider').val()); $('#tacticalSlider').val(Math.round(((myVars.playStyle.tactical - 0.2) / 0.6) * 10)); $('#tacticalValue').text($('#tacticalSlider').val()); $('#positionalSlider').val(Math.round(((myVars.playStyle.positional - 0.2) / 0.6) * 10)); $('#positionalValue').text($('#positionalSlider').val()); } // Update blunder rate slider with saved value if (myVars.blunderRate !== undefined) { $('#blunderRateSlider').val(Math.round(myVars.blunderRate * 10)); $('#blunderRateValue').text($('#blunderRateSlider').val()); } // Set advanced settings based on saved values $('#adaptToRating').prop('checked', myVars.adaptToRating); $('#useOpeningBook').prop('checked', myVars.useOpeningBook); $('#enableHotkeys').prop('checked', myVars.enableHotkeys); $('#randomizeTiming').prop('checked', myVars.randomizeTiming); if (myVars.mouseMovementRealism !== undefined) { $('#mouseMovementSlider').val(Math.round(myVars.mouseMovementRealism * 10)); $('#mouseMovementSliderValue').text($('#mouseMovementSlider').val()); } if (myVars.preferredOpenings && myVars.preferredOpenings.length === 1) { $('#preferredOpeningSelect').val(myVars.preferredOpenings[0]); } // Add event handlers to save settings when they change $('#autoRun, #autoMove, #adaptToRating, #useOpeningBook, #enableHotkeys, #randomizeTiming').on('change', function() { const id = $(this).attr('id'); myVars[id] = $(this).prop('checked'); myFunctions.saveSettings(); }); $('#depthSlider').on('input', function() { // The existing handler already updates the UI myFunctions.saveSettings(); }); $('#timeDelayMin, #timeDelayMax').on('change', function() { myFunctions.saveSettings(); }); $('.style-slider').on('input', function() { // The existing handler updates the playStyle object myFunctions.saveSettings(); }); $('#highlightColor').on('input', function() { // Existing handler already updates myVars.highlightColor myFunctions.saveSettings(); }); $('#preferredOpeningSelect').on('change', function() { // Existing handler updates preferredOpenings myFunctions.saveSettings(); }); $('#playingProfileSelect').on('change', function() { // After profile is applied setTimeout(myFunctions.saveSettings, 100); }); $('#autoMove').on('change', function() { myVars.autoMove = $(this).prop('checked'); console.log(`Auto move set to: ${myVars.autoMove}`); myFunctions.saveSettings(); }); loaded = true; } catch (error) {console.log(error)} } function other(delay) { // Create more natural timing pattern based on game situation const gamePhase = estimateGamePhase(); const positionComplexity = estimatePositionComplexity(); // Apply more realistic timing adjustments let naturalDelay = delay; // Faster moves in openings if (gamePhase < 10) { naturalDelay *= (0.6 + Math.random() * 0.4); } // Slower in complex positions if (positionComplexity > 0.7) { naturalDelay *= (1 + Math.random() * 1.5); } // Add slight additional randomness naturalDelay *= (0.85 + Math.random() * 0.3); var endTime = Date.now() + naturalDelay; var timer = setInterval(()=>{ if(Date.now() >= endTime){ myFunctions.autoRun(getAdjustedDepth()); canGo = true; clearInterval(timer); } },10); } function getAdjustedDepth() { // Get time remaining and adjust depth accordingly const timeRemaining = estimateTimeRemaining(); const gamePhase = estimateGamePhase(); const positionType = analyzePositionType(board.game.getFEN()); const isPositionCritical = isPositionCriticalNow(); // Base depth from slider let baseDepth = lastValue; // Time-based adjustments if (timeRemaining < 30) { // Below 30 seconds - use very low depth return Math.floor(Math.random() * 3) + 1; // 1-3 } else if (timeRemaining < 60) { // Below 1 minute - use low depth return Math.floor(Math.random() * 3) + 5; // 5-7 } // Game phase adjustments if (gamePhase < 10) { // Opening phase - use lower depth baseDepth = Math.min(baseDepth, 10); } else if (gamePhase > 30) { // Endgame - can use higher depth as positions are simpler baseDepth = Math.min(baseDepth + 2, 20); } // Occasionally use very low depth to prevent detection if (!isPositionCritical && Math.random() < 0.15) { return Math.floor(Math.random() * 2) + 2; // 2-3 } // Add some randomness to the depth const variation = Math.floor(Math.random() * 5) - 2; // -2 to +2 return Math.max(1, Math.min(20, baseDepth + variation)); } function isPositionCriticalNow() { // Determine if the current position is critical // This is a simplified implementation try { // Check if kings are under attack const inCheck = board.game.inCheck(); // Check material balance (simplified) const fen = board.game.getFEN(); const whiteMaterial = countMaterial(fen, true); const blackMaterial = countMaterial(fen, false); const materialDifference = Math.abs(whiteMaterial - blackMaterial); // Position is critical if in check or material is close return inCheck || materialDifference < 2; } catch (e) { return false; } } function countMaterial(fen, isWhite) { // Simple material counting function const position = fen.split(' ')[0]; let material = 0; const pieces = isWhite ? 'PNBRQK' : 'pnbrqk'; const values = { 'P': 1, 'N': 3, 'B': 3, 'R': 5, 'Q': 9, 'K': 0, 'p': 1, 'n': 3, 'b': 3, 'r': 5, 'q': 9, 'k': 0 }; for (let char of position) { if (pieces.includes(char)) { material += values[char]; } } return material; } async function getVersion(){ var GF = new GreasyFork; // set upping api var code = await GF.get().script().code(531100); // Get code var version = GF.parseScriptCodeMeta(code).filter(e => e.meta === '@version')[0].value; // filtering array and getting value of @version if(currentVersion !== version){ while(true){ alert('UPDATE THIS SCRIPT IN ORDER TO PROCEED!'); } } } //Removed due to script being reported. I tried to make it so people can know when bug fixes come out. Clearly people don't like that. //getVersion(); const waitForChessBoard = setInterval(() => { if(loaded) { board = $('chess-board')[0] || $('wc-chess-board')[0]; myVars.autoRun = $('#autoRun')[0].checked; myVars.autoMove = $('#autoMove')[0].checked; let minDel = parseFloat($('#timeDelayMin')[0].value); let maxDel = parseFloat($('#timeDelayMax')[0].value); myVars.delay = Math.random() * (maxDel - minDel) + minDel; myVars.isThinking = isThinking; myFunctions.spinner(); if(board.game.getTurn() == board.game.getPlayingAs()){myTurn = true;} else {myTurn = false;} $('#depthText')[0].innerHTML = "Current Depth: "+lastValue+""; } else { myFunctions.loadEx(); } if(!engine.engine){ myFunctions.loadChessEngine(); } if(myVars.autoRun == true && canGo == true && isThinking == false && myTurn){ //console.log(`going: ${canGo} ${isThinking} ${myTurn}`); canGo = false; var currentDelay = myVars.delay != undefined ? myVars.delay * 1000 : 10; other(currentDelay); } }, 100); // Add these two functions for saving and loading settings myFunctions.saveSettings = function() { GM_setValue('autoRun', myVars.autoRun); GM_setValue('autoMove', myVars.autoMove); GM_setValue('timeDelayMin', $('#timeDelayMin').val()); GM_setValue('timeDelayMax', $('#timeDelayMax').val()); GM_setValue('depthValue', lastValue); GM_setValue('highlightColor', myVars.highlightColor); GM_setValue('playStyle', myVars.playStyle); GM_setValue('blunderRate', myVars.blunderRate); GM_setValue('adaptToRating', myVars.adaptToRating); GM_setValue('useOpeningBook', myVars.useOpeningBook); GM_setValue('preferredOpenings', myVars.preferredOpenings); GM_setValue('enableHotkeys', myVars.enableHotkeys); GM_setValue('randomizeTiming', myVars.randomizeTiming); GM_setValue('mouseMovementRealism', myVars.mouseMovementRealism); myFunctions.saveGameMemory(result, opponent, mistakes); myVars.openingRepertoire = GM_getValue('openingRepertoire', { white: { main: getRandomOpenings(2), experimental: getRandomOpenings(3, true), success: {} }, black: { responses: { e4: getRandomResponses('e4', 2), d4: getRandomResponses('d4', 2), c4: getRandomResponses('c4', 2), other: getRandomResponses('other', 2) }, success: {} }, lastUpdated: Date.now() }); updateOpeningRepertoire(); }; myFunctions.loadSettings = function() { myVars.autoRun = GM_getValue('autoRun', false); myVars.autoMove = GM_getValue('autoMove', false); $('#timeDelayMin').val(GM_getValue('timeDelayMin', 0.1)); $('#timeDelayMax').val(GM_getValue('timeDelayMax', 1)); lastValue = GM_getValue('depthValue', 11); myVars.highlightColor = GM_getValue('highlightColor', 'rgb(235, 97, 80)'); myVars.playStyle = GM_getValue('playStyle', { aggressive: Math.random() * 0.5 + 0.3, defensive: Math.random() * 0.5 + 0.3, tactical: Math.random() * 0.6 + 0.2, positional: Math.random() * 0.6 + 0.2 }); myVars.blunderRate = GM_getValue('blunderRate', 0.05); myVars.adaptToRating = GM_getValue('adaptToRating', true); myVars.useOpeningBook = GM_getValue('useOpeningBook', true); myVars.preferredOpenings = GM_getValue('preferredOpenings', ["e4", "d4", "c4", "Nf3"]); myVars.enableHotkeys = GM_getValue('enableHotkeys', true); myVars.randomizeTiming = GM_getValue('randomizeTiming', true); myVars.mouseMovementRealism = GM_getValue('mouseMovementRealism', 0.7); }; myFunctions.saveGameMemory = function(result, opponent, mistakes) { // Get existing memory let gameMemory = GM_getValue('gameMemory', { openingSuccess: {}, opponentHistory: {}, mistakePositions: [] }); // Store opening success rate const opening = board.game.pgn.split('\n\n')[1].split(' ').slice(0, 6).join(' '); if (!gameMemory.openingSuccess[opening]) { gameMemory.openingSuccess[opening] = { wins: 0, losses: 0, draws: 0 }; } gameMemory.openingSuccess[opening][result]++; // Record opponent data if (!gameMemory.opponentHistory[opponent]) { gameMemory.opponentHistory[opponent] = { games: 0, style: 'unknown' }; } gameMemory.opponentHistory[opponent].games++; // Store mistake patterns for future reference if (mistakes && mistakes.length) { gameMemory.mistakePositions = gameMemory.mistakePositions.concat(mistakes).slice(-50); } GM_setValue('gameMemory', gameMemory); }; function getThinkingTime(position) { const baseTime = parseFloat($('#timeDelayMin').val()) * 1000; const maxTime = parseFloat($('#timeDelayMax').val()) * 1000; // Analyze position const complexity = calculatePositionComplexity(position); // 0-1 const criticalness = determinePositionCriticalness(position); // 0-1 const familiarity = assessPositionFamiliarity(position); // 0-1 // Human-like time scaling let thinkingTime = baseTime; // Complex positions take more time thinkingTime += complexity * (maxTime - baseTime) * 0.7; // Critical positions deserve more attention thinkingTime += criticalness * (maxTime - baseTime) * 0.5; // Unfamiliar positions need more thought thinkingTime += (1 - familiarity) * (maxTime - baseTime) * 0.3; // Avoid predictable timing with small random variation thinkingTime *= 0.85 + Math.random() * 0.3; return Math.min(maxTime * 1.2, thinkingTime); } // Add placeholder functions that can be expanded function calculatePositionComplexity(position) { // Count material, tension, possible tactics const pieceCount = position.split(/[prnbqkPRNBQK]/).length - 1; const hasQueen = position.includes('q') || position.includes('Q'); const pawnStructure = analyzeBasicPawnStructure(position); return Math.min(1, (pieceCount / 32) + (hasQueen ? 0.2 : 0) + pawnStructure * 0.3); } function adjustEngineEvaluation(position, move, evaluation) { // Apply player's strategic preferences const adjustedEval = { ...evaluation }; // Adjust based on fingerprint if (myVars.playerFingerprint.favoredPieces === 'knights' && move.includes('N')) { adjustedEval.score += 0.05 + Math.random() * 0.1; } if (myVars.playerFingerprint.favoredPieces === 'bishops' && move.includes('B')) { adjustedEval.score += 0.05 + Math.random() * 0.1; } // Kingside/queenside attack preference if (myVars.playerFingerprint.attackingStyle === 'kingside' && isKingsideMove(move)) { adjustedEval.score += 0.07 + Math.random() * 0.08; } // Occasionally have a "brilliant" insight (1-2% of moves) if (Math.random() < 0.015) { // Temporary increase in effective depth for this move evaluation console.log("Brilliant insight detected!"); return getDeepEvaluation(position, move); } return adjustedEval; } function isEndgame(position) { // Basic endgame detection const pieceCount = position.split(/[prnbqkPRNBQK]/).length - 1; return pieceCount <= 10; } function adjustEndgamePlay(fen, moves) { if (!isEndgame(fen)) return moves; // Common human endgame patterns const hasKingActivity = increasesKingActivity(moves[0], fen); const promotionPotential = evaluatePromotionPotential(fen); // King opposition knowledge (common human knowledge) if (hasKingOpposition(fen) && Math.random() < 0.9) { // Humans typically understand king opposition return prioritizeOppositionMoves(moves); } // Activate king in endgames (humans know this) if (hasKingActivity && Math.random() < 0.75) { return moves; // Keep the engine's correct evaluation } else if (hasKingActivity) { // Sometimes miss the importance of king activity return [moves[1] || moves[0], ...moves.slice(1)]; } // Humans tend to focus on pawn promotion if (promotionPotential > 0.7) { return prioritizePawnAdvancement(moves); } return moves; } // Add to myVars at initialization myVars.psychologicalState = { confidence: 0.7 + Math.random() * 0.3, // 0.7-1.0 tiltFactor: 0, // 0-1, increases with blunders focus: 0.8 + Math.random() * 0.2, // 0.8-1.0, decreases with time playTime: 0 // tracks continuous play time }; // Update in a function that runs periodically function updatePsychologicalState(gameState) { // Increase play time myVars.psychologicalState.playTime += 1; // Focus decreases with time (mental fatigue) if (myVars.psychologicalState.playTime > 10) { myVars.psychologicalState.focus = Math.max(0.5, myVars.psychologicalState.focus - 0.01); } // Check for blunders in recent moves if (detectBlunder(gameState)) { // Increase tilt after mistakes myVars.psychologicalState.tiltFactor = Math.min(1, myVars.psychologicalState.tiltFactor + 0.25); myVars.psychologicalState.confidence = Math.max(0.3, myVars.psychologicalState.confidence - 0.15); } // Good moves restore confidence if (detectGoodMove(gameState)) { myVars.psychologicalState.confidence = Math.min(1, myVars.psychologicalState.confidence + 0.05); myVars.psychologicalState.tiltFactor = Math.max(0, myVars.psychologicalState.tiltFactor - 0.1); } // Apply psychological state to blunder rate const effectiveBlunderRate = myVars.blunderRate * (1 + myVars.psychologicalState.tiltFactor) * (2 - myVars.psychologicalState.focus); return effectiveBlunderRate; } function detectTimeControl() { try { // Look for the clock element and determine time control const clockEl = document.querySelector('.clock-component'); if (clockEl) { const timeText = clockEl.textContent; const minutes = parseInt(timeText.split(':')[0]); if (minutes >= 15) return 'classical'; if (minutes >= 5) return 'rapid'; return 'blitz'; } } catch (e) {} return 'rapid'; // Default } function adaptToTimeControl() { const timeControl = detectTimeControl(); switch (timeControl) { case 'blitz': // More intuitive play, faster moves, higher blunder rate myVars.blunderRate *= 1.3; $('#timeDelayMin').val(Math.max(0.1, parseFloat($('#timeDelayMin').val()) * 0.7)); $('#timeDelayMax').val(Math.max(0.3, parseFloat($('#timeDelayMax').val()) * 0.7)); // Use more recognizable patterns and opening theory myVars.patternRecognitionWeight = 0.8; break; case 'rapid': // Balanced approach myVars.patternRecognitionWeight = 0.6; break; case 'classical': // More calculation, deeper search, fewer blunders myVars.blunderRate *= 0.7; $('#timeDelayMin').val(parseFloat($('#timeDelayMin').val()) * 1.2); $('#timeDelayMax').val(parseFloat($('#timeDelayMax').val()) * 1.3); // More unique moves, less reliance on patterns myVars.patternRecognitionWeight = 0.4; break; } } function updateOpeningRepertoire() { // Only update periodically (simulating a player learning new openings) if (Date.now() - myVars.openingRepertoire.lastUpdated < 7 * 24 * 60 * 60 * 1000) { return; // Only update weekly } // Replace worst performing opening with a new one const gameMemory = GM_getValue('gameMemory', { openingSuccess: {} }); // Find worst performing opening let worstScore = Infinity; let worstOpening = null; for (const opening in gameMemory.openingSuccess) { const stats = gameMemory.openingSuccess[opening]; const score = stats.wins - stats.losses; if (score < worstScore && stats.wins + stats.losses + stats.draws >= 5) { worstScore = score; worstOpening = opening; } } // Replace it if we found a bad one if (worstOpening && worstScore < 0) { console.log("Phasing out unprofitable opening: " + worstOpening); // Replace with a new experimental opening if (worstOpening.startsWith('1.')) { // It's a white opening myVars.openingRepertoire.white.experimental = myVars.openingRepertoire.white.experimental.filter(o => o !== worstOpening); myVars.openingRepertoire.white.experimental.push(getRandomOpenings(1, true)[0]); } else { // It's a black response // Implementation would be similar to white } } myVars.openingRepertoire.lastUpdated = Date.now(); GM_setValue('openingRepertoire', myVars.openingRepertoire); } // Then when evaluating positions: function adjustForTacticalProfile(moves, position) { for (let i = 0; i < moves.length; i++) { const tacticalMotif = identifyTacticalMotif(moves[i], position); // Boost strengths if (myVars.tacticalProfile.strengths.includes(tacticalMotif)) { // Higher chance of finding this tactic if (i > 0 && Math.random() < 0.8) { // Swap with the first move (more likely to be played) [moves[0], moves[i]] = [moves[i], moves[0]]; } } // Miss weaknesses if (myVars.tacticalProfile.weaknesses.includes(tacticalMotif)) { // Higher chance of missing this tactic if (i === 0 && moves.length > 1 && Math.random() < 0.7) { // Swap with the second move (less likely to be played) [moves[0], moves[1]] = [moves[1], moves[0]]; } } } return moves; } } //Touching below may break the script var isThinking = false var canGo = true; var myTurn = false; var board; window.addEventListener("load", (event) => { let currentTime = Date.now(); main(); }); function getAppropriateDepth() { // Get player's rating if available let playerRating = 1500; // Default try { const ratingEl = document.querySelector('.user-tagline-rating'); if (ratingEl) { playerRating = parseInt(ratingEl.textContent); } } catch (e) {} // Map ratings to appropriate depths if (playerRating < 800) return Math.floor(Math.random() * 3) + 1; // 1-3 if (playerRating < 1200) return Math.floor(Math.random() * 3) + 3; // 3-5 if (playerRating < 1600) return Math.floor(Math.random() * 3) + 5; // 5-7 if (playerRating < 2000) return Math.floor(Math.random() * 3) + 7; // 7-9 if (playerRating < 2400) return Math.floor(Math.random() * 4) + 9; // 9-12 return Math.floor(Math.random() * 5) + 12; // 12-16 } function getBezierPoint(t, p0, p1, p2, p3) { const cX = 3 * (p1.x - p0.x); const bX = 3 * (p2.x - p1.x) - cX; const aX = p3.x - p0.x - cX - bX; const cY = 3 * (p1.y - p0.y); const bY = 3 * (p2.y - p1.y) - cY; const aY = p3.y - p0.y - cY - bY; const x = (aX * Math.pow(t, 3)) + (bX * Math.pow(t, 2)) + (cX * t) + p0.x; const y = (aY * Math.pow(t, 3)) + (bY * Math.pow(t, 2)) + (cY * t) + p0.y; return { x, y }; } function executeMouseMovement(points, index, delay, callback) { if (index >= points.length) { if (callback) callback(); return; } // Simulate mouse movement const point = points[index]; // In a real implementation, you would trigger actual mouse events // For our purposes, we'll just move to the next point setTimeout(() => { executeMouseMovement(points, index + 1, delay, callback); }, delay); } function getSquarePosition(square) { // Convert chess notation (e.g., "e4") to screen coordinates // This is a simplified version - in reality, you'd need to get actual board coordinates const file = square.charCodeAt(0) - 'a'.charCodeAt(0); const rank = parseInt(square.charAt(1)) - 1; // Get board dimensions const boardRect = board.getBoundingClientRect(); const squareSize = boardRect.width / 8; // Calculate center of the square const x = boardRect.left + (file + 0.5) * squareSize; const y = boardRect.top + (7 - rank + 0.5) * squareSize; return { x, y }; }