Greasy Fork is available in English.

Chess.com Bot/Cheat (by Wayron)

Chess.com Bot/Cheat that finds the best move!

As of 19.05.2025. See ბოლო ვერსია.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

  1. // ==UserScript==
  2. // @name Chess.com Bot/Cheat (by Wayron)
  3. // @namespace Admin0
  4. // @version 1.1.0
  5. // @description Chess.com Bot/Cheat that finds the best move!
  6. // @author Admin0
  7. // @license Chess.com Bot/Cheat © 2024 by Admin0, © All Rights Reserved
  8. // @match https://www.chess.com/play/*
  9. // @match https://www.chess.com/game/*
  10. // @match https://www.chess.com/puzzles/*
  11. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_xmlhttpRequest
  15. // @grant GM_getResourceText
  16. // @grant GM_registerMenuCommand
  17. // @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/9.0.0/stockfish.js
  18. // @require https://greatest.deepsurf.us/scripts/445697/code/index.js
  19. // @require https://code.jquery.com/jquery-3.6.0.min.js
  20. // @run-at document-start
  21. // ==/UserScript==
  22.  
  23. // CLEAN REWRITE - CHESS.COM THEMED VERSION 3.0
  24.  
  25. const currentVersion = '3.0';
  26.  
  27. function main() {
  28. // Core variables setup
  29. var stockfishObjectURL;
  30. var engine = document.engine = {};
  31. var myVars = document.myVars = {};
  32. myVars.autoMove = GM_getValue('autoMove', false); // Load saved autoMove
  33. myVars.suggestMove = GM_getValue('suggestMove', false); // Load saved suggestMove
  34. myVars.autoMatch = GM_getValue('autoMatch', false); // Load saved autoMatch
  35. myVars.customDepth = GM_getValue('customDepth', 11); // Load saved depth, default to 11
  36. myVars.bestMoveHighlightColor = GM_getValue('bestMoveHighlightColor', '#7fa650'); // Chess.com green
  37. var myFunctions = document.myFunctions = {};
  38. var lastValue = GM_getValue('customDepth', 11); // Also initialize lastValue with saved/default depth
  39.  
  40. // Core chess engine logic from Script3 (the working one)
  41. myFunctions.color = function(dat) {
  42. console.log("[Move] Processing:", dat);
  43. console.log("[Highlight] Attempting highlight on board element:", board ? board.nodeName : 'Board not found!'); // Diagnostic log
  44. let response = dat;
  45. let res1 = response.substring(0, 2); // From square
  46. let res2 = response.substring(2, 4); // To square
  47.  
  48. // Execute move if auto-move is enabled
  49. if (myVars.autoMove === true) {
  50. myFunctions.movePiece(res1, res2);
  51. }
  52.  
  53. // Reset thinking state
  54. isThinking = false;
  55.  
  56. // Convert chess notation to Chess.com's grid system
  57. res1 = res1.replace(/^a/, "1")
  58. .replace(/^b/, "2")
  59. .replace(/^c/, "3")
  60. .replace(/^d/, "4")
  61. .replace(/^e/, "5")
  62. .replace(/^f/, "6")
  63. .replace(/^g/, "7")
  64. .replace(/^h/, "8");
  65. res2 = res2.replace(/^a/, "1")
  66. .replace(/^b/, "2")
  67. .replace(/^c/, "3")
  68. .replace(/^d/, "4")
  69. .replace(/^e/, "5")
  70. .replace(/^f/, "6")
  71. .replace(/^g/, "7")
  72. .replace(/^h/, "8");
  73.  
  74. // Highlight destination square
  75. $(board.nodeName)
  76. .prepend('<div class="highlight square-' + res2 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0.7;" data-test-element="highlight"></div>')
  77. .children(':first')
  78. .delay(1800)
  79. .queue(function() {
  80. $(this).remove();
  81. });
  82.  
  83. // Highlight origin square
  84. $(board.nodeName)
  85. .prepend('<div class="highlight square-' + res1 + ' bro" style="background-color: ' + myVars.bestMoveHighlightColor + '; opacity: 0.7;" data-test-element="highlight"></div>')
  86. .children(':first')
  87. .delay(1800)
  88. .queue(function() {
  89. $(this).remove();
  90. });
  91. };
  92.  
  93. // Move execution function from Script3
  94. myFunctions.movePiece = function(from, to) {
  95. console.log("[Move] Executing move from", from, "to", to);
  96. try {
  97. // Get legal moves from the game
  98. let legalMoves = board.game.getLegalMoves();
  99.  
  100. // Find our move in legal moves
  101. for (let each = 0; each < legalMoves.length; each++) {
  102. if (legalMoves[each].from === from && legalMoves[each].to === to) {
  103. let move = legalMoves[each];
  104.  
  105. // Check for promotion (pawn to last rank)
  106. let promotion = undefined;
  107. let piece = board.game.getPiece(from);
  108. if (piece && piece.type === 'p' && (to[1] === '8' || to[1] === '1')) {
  109. promotion = 'q'; // Default promote to queen
  110. console.log("[Move] Promoting pawn to queen");
  111. }
  112.  
  113. // Execute the move
  114. board.game.move({
  115. from: move.from,
  116. to: move.to,
  117. promotion: promotion,
  118. animate: false,
  119. userGenerated: true
  120. });
  121. console.log("[Move] Executed successfully");
  122. return;
  123. }
  124. }
  125. console.warn("[Move] No legal move found:", from, to);
  126. } catch (error) {
  127. console.error("[Move] Error executing move:", error);
  128. }
  129. };
  130.  
  131. // Parser from Script3
  132. function parser(e) {
  133. console.log("[Engine] Message:", e.data);
  134. if (e.data.includes('bestmove')) {
  135. console.log("[Engine] Found best move:", e.data);
  136. myFunctions.color(e.data.split(' ')[1]);
  137. isThinking = false;
  138. }
  139. }
  140.  
  141. // Engine load function from Script3
  142. myFunctions.loadChessEngine = function() {
  143. console.log("[Engine] Loading Stockfish...");
  144. try {
  145. if (!stockfishObjectURL) {
  146. stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
  147. }
  148.  
  149. engine.engine = new Worker(stockfishObjectURL);
  150.  
  151. engine.engine.onmessage = e => {
  152. parser(e);
  153. };
  154.  
  155. engine.engine.onerror = e => {
  156. console.error("[Engine] Error:", e);
  157. isThinking = false;
  158. };
  159.  
  160. engine.engine.postMessage('ucinewgame');
  161. console.log("[Engine] Loaded successfully");
  162. } catch (error) {
  163. console.error("[Engine] Load failed:", error);
  164. }
  165. };
  166.  
  167. // Engine reload function
  168. myFunctions.reloadChessEngine = function() {
  169. console.log("[Engine] Reloading...");
  170. try {
  171. if (engine.engine) {
  172. engine.engine.terminate();
  173. }
  174. isThinking = false;
  175. stockfishObjectURL = null; // Force recreation
  176. setTimeout(() => {
  177. myFunctions.loadChessEngine();
  178. console.log("[Engine] Reloaded successfully");
  179. }, 100);
  180. } catch (error) {
  181. console.error("[Engine] Reload failed:", error);
  182. }
  183. };
  184.  
  185. // Run engine at specified depth
  186. myFunctions.runChessEngine = function(depth) {
  187. console.log("[Engine] Running at depth", depth);
  188. let fen = board.game.getFEN();
  189. console.log("[Engine] Position:", fen);
  190.  
  191. engine.engine.postMessage(`position fen ${fen}`);
  192. isThinking = true;
  193. engine.engine.postMessage(`go depth ${depth}`);
  194. lastValue = depth;
  195. };
  196.  
  197. // Auto run function
  198. myFunctions.autoRun = function(depth) {
  199. if (board.game.getTurn() == board.game.getPlayingAs()) {
  200. myFunctions.runChessEngine(depth || myVars.customDepth);
  201. }
  202. };
  203.  
  204. // Function to handle delayed auto-run
  205. function other(delay) {
  206. let endTime = Date.now() + delay;
  207. let timer = setInterval(() => {
  208. if (Date.now() >= endTime) {
  209. myFunctions.autoRun(myVars.customDepth);
  210. canGo = true;
  211. clearInterval(timer);
  212. }
  213. }, 10);
  214. }
  215.  
  216. // Auto start new game
  217. myFunctions.startNewGame = function() {
  218. console.log("[Match] Starting new game...");
  219.  
  220. // Find New Game button in different places
  221. const modalNewGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  222. if (modalNewGameButton.length) {
  223. modalNewGameButton[0].click();
  224. console.log("[Match] Clicked New Game from modal");
  225. myVars.hasAutoMatched = true;
  226. myVars.gameEnded = false;
  227. return;
  228. }
  229.  
  230. const newGameButton = $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  231. if (newGameButton.length) {
  232. newGameButton[0].click();
  233. console.log("[Match] Clicked New Game button");
  234. myVars.hasAutoMatched = true;
  235. myVars.gameEnded = false;
  236. return;
  237. }
  238.  
  239. console.log("[Match] No New Game button found");
  240. };
  241.  
  242. // Function to handle spinner visibility
  243. myFunctions.spinner = function() {
  244. if (loaded && $('#overlay').length) {
  245. $('#overlay').css('display', isThinking ? 'block' : 'none');
  246. }
  247. };
  248.  
  249. // Handle keyboard shortcuts
  250. document.onkeydown = function(e) {
  251. const depthKeys = {
  252. 81: 1, 87: 2, 69: 3, 82: 4, 84: 5, 89: 6, 85: 7, 73: 8, 79: 9, 80: 10,
  253. 65: 11, 83: 12, 68: 13, 70: 14, 71: 15, 72: 16, 74: 17, 75: 18, 76: 19,
  254. 90: 20, 88: 21, 67: 22, 86: 23, 66: 24, 78: 25, 77: 26, 187: 100
  255. };
  256.  
  257. if (depthKeys[e.keyCode]) {
  258. myVars.customDepth = depthKeys[e.keyCode];
  259. if (loaded) {
  260. $('#depthValue').text(myVars.customDepth);
  261. }
  262. GM_setValue('customDepth', myVars.customDepth); // Save the new depth
  263. location.reload(); // Reload the page
  264. }
  265.  
  266. // Toggle UI with ESC
  267. if (e.keyCode === 27 && loaded) {
  268. $('#chessBot').toggle();
  269. }
  270. };
  271.  
  272. // UI Creation function - CHESS.COM THEMED
  273. var loaded = false;
  274. myFunctions.loadEx = function() {
  275. if (loaded) return;
  276.  
  277. try {
  278. console.log("[UI] Creating Chess.com themed interface...");
  279. board = $('chess-board')[0] || $('wc-chess-board')[0];
  280. if (!board) {
  281. console.warn("[UI] Board not found yet");
  282. return;
  283. }
  284.  
  285. myVars.board = board;
  286.  
  287. // Create main container with Chess.com styling
  288. const panel = document.createElement('div');
  289. panel.id = 'chessBot';
  290. panel.style = `
  291. position: fixed;
  292. right: 20px;
  293. top: 50%;
  294. transform: translateY(-50%);
  295. width: 280px;
  296. background-color: #312e2b;
  297. color: #bababa;
  298. font-family: "Segoe UI", Arial, sans-serif;
  299. z-index: 9999;
  300. padding: 15px;
  301. border-radius: 5px;
  302. box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
  303. font-size: 14px;
  304. `;
  305.  
  306. // Create header
  307. const header = document.createElement('div');
  308. header.style = `
  309. display: flex;
  310. justify-content: space-between;
  311. align-items: center;
  312. margin-bottom: 15px;
  313. border-bottom: 1px solid #464442;
  314. padding-bottom: 10px;
  315. `;
  316.  
  317. const title = document.createElement('h2');
  318. title.innerText = 'Chess.com Bot';
  319. title.style = `
  320. margin: 0;
  321. font-size: 18px;
  322. font-weight: 600;
  323. color: #bababa;
  324. `;
  325.  
  326. const version = document.createElement('span');
  327. version.innerText = 'v3.0';
  328. version.style = `
  329. font-size: 12px;
  330. opacity: 0.8;
  331. color: #bababa;
  332. `;
  333.  
  334. header.appendChild(title);
  335. header.appendChild(version);
  336. panel.appendChild(header);
  337.  
  338. // Create spinner overlay
  339. const overlay = document.createElement('div');
  340. overlay.id = 'overlay';
  341. overlay.style = `
  342. position: absolute;
  343. top: 0;
  344. left: 0;
  345. right: 0;
  346. bottom: 0;
  347. background-color: rgba(49, 46, 43, 0.85);
  348. z-index: 10000;
  349. display: none;
  350. border-radius: 5px;
  351. `;
  352.  
  353. const spinner = document.createElement('div');
  354. spinner.style = `
  355. position: absolute;
  356. top: 50%;
  357. left: 50%;
  358. width: 40px;
  359. height: 40px;
  360. margin-top: -20px;
  361. margin-left: -20px;
  362. border: 3px solid #bababa;
  363. border-top-color: #7fa650;
  364. border-radius: 50%;
  365. animation: spin 1s infinite linear;
  366. `;
  367.  
  368. const spinStyle = document.createElement('style');
  369. spinStyle.textContent = `
  370. @keyframes spin {
  371. 0% { transform: rotate(0deg); }
  372. 100% { transform: rotate(360deg); }
  373. }
  374. `;
  375.  
  376. document.head.appendChild(spinStyle);
  377. overlay.appendChild(spinner);
  378. panel.appendChild(overlay);
  379.  
  380. // Create content sections
  381. const createSection = (title) => {
  382. const section = document.createElement('div');
  383. section.style = `
  384. margin-bottom: 15px;
  385. `;
  386.  
  387. const sectionTitle = document.createElement('h3');
  388. sectionTitle.innerText = title;
  389. sectionTitle.style = `
  390. margin: 0 0 10px 0;
  391. font-size: 16px;
  392. color: #bababa;
  393. border-bottom: 1px solid #464442;
  394. padding-bottom: 5px;
  395. `;
  396.  
  397. section.appendChild(sectionTitle);
  398. return section;
  399. };
  400.  
  401. // Create depth section
  402. const depthSection = createSection('Engine Depth');
  403.  
  404. const depthDisplay = document.createElement('div');
  405. depthDisplay.style = `
  406. display: flex;
  407. justify-content: space-between;
  408. align-items: center;
  409. margin-bottom: 10px;
  410. background-color: #3a3634;
  411. padding: 8px 12px;
  412. border-radius: 4px;
  413. `;
  414.  
  415. const depthLabel = document.createElement('span');
  416. depthLabel.innerText = 'Current Depth:';
  417.  
  418. const depthValue = document.createElement('span');
  419. depthValue.id = 'depthValue';
  420. depthValue.innerText = myVars.customDepth;
  421. depthValue.style = `
  422. font-weight: bold;
  423. color: #7fa650;
  424. `;
  425.  
  426. depthDisplay.appendChild(depthLabel);
  427. depthDisplay.appendChild(depthValue);
  428.  
  429. const depthInfo = document.createElement('p');
  430. depthInfo.innerText = 'Press A-Z keys to change depth (Q=1, W=2, etc.)';
  431. depthInfo.style = `
  432. margin: 5px 0;
  433. font-size: 12px;
  434. opacity: 0.7;
  435. `;
  436.  
  437. const depthInput = document.createElement('div');
  438. depthInput.style = `
  439. display: flex;
  440. align-items: center;
  441. margin-top: 10px;
  442. `;
  443.  
  444. const depthInputLabel = document.createElement('label');
  445. depthInputLabel.innerText = 'Set Depth:';
  446. depthInputLabel.style = 'margin-right: 10px;';
  447.  
  448. const depthInputField = document.createElement('input');
  449. depthInputField.type = 'number';
  450. depthInputField.id = 'customDepthInput';
  451. depthInputField.min = '1';
  452. depthInputField.max = '100';
  453. depthInputField.value = myVars.customDepth;
  454. depthInputField.style = `
  455. background-color: #3a3634;
  456. border: 1px solid #464442;
  457. color: #bababa;
  458. padding: 5px;
  459. border-radius: 3px;
  460. width: 60px;
  461. `;
  462.  
  463. depthInputField.addEventListener('change', function() {
  464. const value = parseInt(this.value);
  465. if (!isNaN(value) && value >= 1 && value <= 100) {
  466. myVars.customDepth = value;
  467. depthValue.innerText = value;
  468. GM_setValue('customDepth', myVars.customDepth); // Save the new depth
  469. location.reload(); // Reload the page
  470. } else {
  471. this.value = GM_getValue('customDepth', 11); // Reset to saved value if input is invalid
  472. }
  473. });
  474.  
  475. depthInput.appendChild(depthInputLabel);
  476. depthInput.appendChild(depthInputField);
  477.  
  478. depthSection.appendChild(depthDisplay);
  479. depthSection.appendChild(depthInfo);
  480. depthSection.appendChild(depthInput);
  481. panel.appendChild(depthSection);
  482.  
  483. // Create game options section
  484. const optionsSection = createSection('Game Options');
  485.  
  486. const createCheckbox = (id, label) => {
  487. const container = document.createElement('div');
  488. container.style = `
  489. display: flex;
  490. align-items: center;
  491. margin-bottom: 10px;
  492. cursor: pointer;
  493. `;
  494.  
  495. const checkbox = document.createElement('input');
  496. checkbox.type = 'checkbox';
  497. checkbox.id = id;
  498. checkbox.style = `
  499. margin-right: 10px;
  500. cursor: pointer;
  501. `;
  502.  
  503. const checkLabel = document.createElement('label');
  504. checkLabel.htmlFor = id;
  505. checkLabel.innerText = label;
  506. checkLabel.style = 'cursor: pointer;';
  507.  
  508. container.appendChild(checkbox);
  509. container.appendChild(checkLabel);
  510. return container;
  511. };
  512.  
  513. const autoRunCheck = createCheckbox('suggestMove', 'Enable Suggested Move');
  514. const autoMoveCheck = createCheckbox('autoMove', 'Enable auto move');
  515. const autoMatchCheck = createCheckbox('autoMatch', 'Enable auto match');
  516.  
  517. optionsSection.appendChild(autoRunCheck);
  518. optionsSection.appendChild(autoMoveCheck);
  519. optionsSection.appendChild(autoMatchCheck);
  520. panel.appendChild(optionsSection);
  521.  
  522. // Set initial state from loaded vars
  523. autoRunCheck.querySelector('input').checked = myVars.suggestMove;
  524. autoMoveCheck.querySelector('input').checked = myVars.autoMove;
  525. autoMatchCheck.querySelector('input').checked = myVars.autoMatch;
  526.  
  527. // Create delay section
  528. const delaySection = createSection('Suggestion Delay');
  529.  
  530. const createDelayInput = (id, label, defaultValue) => {
  531. const container = document.createElement('div');
  532. container.style = `
  533. display: flex;
  534. align-items: center;
  535. margin-bottom: 10px;
  536. `;
  537.  
  538. const inputLabel = document.createElement('label');
  539. inputLabel.htmlFor = id;
  540. inputLabel.innerText = label;
  541. inputLabel.style = `
  542. flex: 1;
  543. `;
  544.  
  545. const input = document.createElement('input');
  546. input.type = 'number';
  547. input.id = id;
  548. input.min = '0.1';
  549. input.step = '0.1';
  550. input.value = defaultValue;
  551. input.style = `
  552. background-color: #3a3634;
  553. border: 1px solid #464442;
  554. color: #bababa;
  555. padding: 5px;
  556. border-radius: 3px;
  557. width: 60px;
  558. `;
  559.  
  560. container.appendChild(inputLabel);
  561. container.appendChild(input);
  562. return container;
  563. };
  564.  
  565. const minDelayInput = createDelayInput('timeDelayMin', 'Min Delay (s):', '0.1');
  566. const maxDelayInput = createDelayInput('timeDelayMax', 'Max Delay (s):', '1.0');
  567.  
  568. delaySection.appendChild(minDelayInput);
  569. delaySection.appendChild(maxDelayInput);
  570. panel.appendChild(delaySection);
  571.  
  572. // Create display section
  573. const displaySection = createSection('Display');
  574.  
  575. const colorContainer = document.createElement('div');
  576. colorContainer.style = `
  577. display: flex;
  578. align-items: center;
  579. `;
  580.  
  581. const colorLabel = document.createElement('label');
  582. colorLabel.htmlFor = 'highlightColorInput';
  583. colorLabel.innerText = 'Highlight Color:';
  584. colorLabel.style = 'flex: 1;';
  585.  
  586. const colorInput = document.createElement('input');
  587. colorInput.type = 'color';
  588. colorInput.id = 'highlightColorInput';
  589. colorInput.value = myVars.bestMoveHighlightColor;
  590. colorInput.style = `
  591. width: 60px;
  592. height: 30px;
  593. padding: 0;
  594. border: none;
  595. background: none;
  596. `;
  597.  
  598. colorInput.addEventListener('change', function() {
  599. myVars.bestMoveHighlightColor = this.value;
  600. GM_setValue('bestMoveHighlightColor', this.value);
  601. });
  602.  
  603. colorContainer.appendChild(colorLabel);
  604. colorContainer.appendChild(colorInput);
  605. displaySection.appendChild(colorContainer);
  606. panel.appendChild(displaySection);
  607.  
  608. // Create buttons section
  609. const actionsSection = createSection('Actions');
  610.  
  611. const createButton = (text, onClick, primary = false) => {
  612. const button = document.createElement('button');
  613. button.innerText = text;
  614. button.addEventListener('click', onClick);
  615. button.style = `
  616. background-color: ${primary ? '#7fa650' : '#5d5955'};
  617. color: #fff;
  618. border: none;
  619. padding: 10px;
  620. margin-bottom: 10px;
  621. border-radius: 3px;
  622. width: 100%;
  623. cursor: pointer;
  624. font-weight: ${primary ? 'bold' : 'normal'};
  625. transition: background-color 0.2s;
  626. `;
  627.  
  628. button.addEventListener('mouseover', function() {
  629. this.style.backgroundColor = primary ? '#8fb761' : '#6e6a66';
  630. });
  631.  
  632. button.addEventListener('mouseout', function() {
  633. this.style.backgroundColor = primary ? '#7fa650' : '#5d5955';
  634. });
  635.  
  636. return button;
  637. };
  638.  
  639. const reloadButton = createButton('Reload Chess Engine', () => myFunctions.reloadChessEngine(), true);
  640. const issueButton = createButton('Report an Issue', () => {
  641. window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0/feedback', '_blank');
  642. });
  643.  
  644. const updateButton = createButton('Check for Updates', () => {
  645. window.open('https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0', '_blank');
  646. });
  647.  
  648. actionsSection.appendChild(reloadButton);
  649. actionsSection.appendChild(issueButton);
  650. actionsSection.appendChild(updateButton);
  651. panel.appendChild(actionsSection);
  652.  
  653. // Add drag handle
  654. const dragHandle = document.createElement('div');
  655. dragHandle.style = `
  656. position: absolute;
  657. top: 0;
  658. left: 0;
  659. right: 0;
  660. height: 15px;
  661. cursor: move;
  662. background-color: rgba(255, 255, 255, 0.05);
  663. border-top-left-radius: 5px;
  664. border-top-right-radius: 5px;
  665. `;
  666.  
  667. // Make panel draggable
  668. let isDragging = false;
  669. let offsetX, offsetY;
  670.  
  671. dragHandle.addEventListener('mousedown', function(e) {
  672. isDragging = true;
  673. offsetX = e.clientX - panel.getBoundingClientRect().left;
  674. offsetY = e.clientY - panel.getBoundingClientRect().top;
  675. });
  676.  
  677. document.addEventListener('mousemove', function(e) {
  678. if (isDragging) {
  679. panel.style.right = 'auto';
  680. panel.style.top = (e.clientY - offsetY) + 'px';
  681. panel.style.left = (e.clientX - offsetX) + 'px';
  682. panel.style.transform = 'none';
  683. }
  684. });
  685.  
  686. document.addEventListener('mouseup', function() {
  687. isDragging = false;
  688. });
  689.  
  690. panel.appendChild(dragHandle);
  691.  
  692. // Add footer
  693. const footer = document.createElement('div');
  694. footer.style = `
  695. margin-top: 15px;
  696. padding-top: 10px;
  697. border-top: 1px solid #464442;
  698. font-size: 12px;
  699. text-align: center;
  700. opacity: 0.7;
  701. `;
  702.  
  703. footer.innerText = 'Press ESC to toggle interface';
  704. panel.appendChild(footer);
  705.  
  706. // Append panel to body
  707. document.body.appendChild(panel);
  708.  
  709. loaded = true;
  710. console.log("[UI] Chess.com themed interface created successfully");
  711. } catch (error) {
  712. console.error("[UI] Error creating interface:", error);
  713. }
  714. };
  715.  
  716. // Main interval loop
  717. const waitForChessBoard = setInterval(() => {
  718. if (loaded) {
  719. board = $('chess-board')[0] || $('wc-chess-board')[0];
  720.  
  721. // Read checkbox states directly from DOM
  722. try {
  723. myVars.suggestMove = document.getElementById('suggestMove').checked;
  724. myVars.autoMove = document.getElementById('autoMove').checked;
  725. myVars.autoMatch = document.getElementById('autoMatch').checked;
  726.  
  727. // Save the current state
  728. GM_setValue('suggestMove', myVars.suggestMove);
  729. GM_setValue('autoMove', myVars.autoMove);
  730. GM_setValue('autoMatch', myVars.autoMatch);
  731.  
  732. // Read delay values
  733. let minDelay = parseFloat(document.getElementById('timeDelayMin').value) || 0.1;
  734. let maxDelay = parseFloat(document.getElementById('timeDelayMax').value) || 1.0;
  735. myVars.delay = Math.random() * (maxDelay - minDelay) + minDelay;
  736. } catch (e) {
  737. console.warn("[UI] Error reading UI state:", e);
  738. }
  739.  
  740. // Update spinner
  741. myVars.isThinking = isThinking;
  742. myFunctions.spinner();
  743.  
  744. // Check for game over
  745. const gameOverModal = $('.game-over-modal-content');
  746. if (gameOverModal.length > 0 && !myVars.gameEnded) {
  747. console.log("[Game] Game over detected");
  748. myVars.gameEnded = true;
  749. myVars.hasAutoMatched = false;
  750. }
  751.  
  752. // Check turn
  753. try {
  754. if (!myVars.gameEnded && board && board.game) {
  755. myTurn = (board.game.getTurn() == board.game.getPlayingAs());
  756. } else {
  757. myTurn = false;
  758. }
  759. } catch (e) {
  760. myTurn = false;
  761. }
  762.  
  763. // Log state (for debugging)
  764. console.log(`[State] SuggestMove:${myVars.suggestMove} AutoMove:${myVars.autoMove} AutoMatch:${myVars.autoMatch} MyTurn:${myTurn} Thinking:${isThinking} CanGo:${canGo}`);
  765.  
  766. // Make sure engine is loaded
  767. if (!engine.engine) {
  768. myFunctions.loadChessEngine();
  769. }
  770.  
  771. // Auto Run Logic (Now Suggested Move Logic)
  772. if (myVars.suggestMove && canGo && !isThinking && myTurn && !myVars.gameEnded) {
  773. console.log("[Auto] Triggering suggested move analysis...");
  774. canGo = false;
  775. const currentDelay = myVars.delay * 1000;
  776. other(currentDelay);
  777. }
  778.  
  779. // Auto Match Logic
  780. if (myVars.autoMatch && myVars.gameEnded && !myVars.hasAutoMatched) {
  781. console.log("[Auto] Triggering auto match...");
  782. myFunctions.startNewGame();
  783. }
  784. } else if ($('chess-board, wc-chess-board').length > 0) {
  785. // Try to load UI if not loaded yet
  786. myFunctions.loadEx();
  787. }
  788. }, 100);
  789. }
  790.  
  791. // Global variables
  792. var isThinking = false;
  793. var canGo = true;
  794. var myTurn = false;
  795. var board;
  796.  
  797. // Start the script
  798. window.addEventListener("load", (event) => {
  799. console.log("[Script] Chess.com Bot v3.0 starting...");
  800. main();
  801. });