Chess.com Bot/Cheat (by Admin0)

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

As of 2025-04-26. See the latest version.

  1. // additional copyright/license info:
  2. //© All Rights Reserved
  3. //
  4. //Chess.com Cheat/Bot © 2023 by Admin0
  5. //
  6. // ==UserScript==
  7. // @name Chess.com Bot/Cheat (by Admin0)
  8. // @namespace Admin0
  9. // @version 2.1
  10. // @description Chess.com Bot/Cheat that finds the best move!
  11. // @author Admin0
  12. // @license Chess.com Bot/Cheat © 2024 by Admin0, © All Rights Reserved
  13. // @match https://www.chess.com/play/*
  14. // @match https://www.chess.com/game/*
  15. // @match https://www.chess.com/puzzles/*
  16. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // @grant GM_xmlhttpRequest
  20. // @grant GM_getResourceText
  21. // @grant GM_registerMenuCommand
  22. // @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/9.0.0/stockfish.js
  23. // @require https://greatest.deepsurf.us/scripts/445697/code/index.js
  24. // @require https://code.jquery.com/jquery-3.6.0.min.js
  25. // @run-at document-start
  26. // ==/UserScript==
  27.  
  28. // SCRIPT // DO NOT CHANGE //
  29.  
  30. const currentVersion = '1'; // Sets the current version
  31.  
  32. function main() {
  33.  
  34. var stockfishObjectURL;
  35. var engine = document.engine = {};
  36. var myVars = document.myVars = {};
  37. myVars.autoMovePiece = false;
  38. myVars.autoRun = false;
  39. myVars.autoMove = false;
  40. myVars.autoMatch = false;
  41. myVars.delay = 0.1;
  42. myVars.customDepth = 11;
  43. myVars.hasAutoMatched = false;
  44. myVars.gameEnded = false;
  45. myVars.isAttemptingAutoMatch = false;
  46. // Load saved highlight color or set default
  47. myVars.bestMoveHighlightColor = GM_getValue('bestMoveHighlightColor', '#EB6150'); // Default: rgb(235, 97, 80)
  48. // Threat Highlighting vars - REMOVED
  49. // myVars.enableThreatHighlighting = GM_getValue('enableThreatHighlighting', false);
  50. // myVars.threatHighlightColor = GM_getValue('threatHighlightColor', '#FFDB58');
  51. // myVars.lastOpponentMove = null;
  52. var myFunctions = document.myFunctions = {};
  53.  
  54.  
  55. stop_b = stop_w = 0;
  56. s_br = s_br2 = s_wr = s_wr2 = 0;
  57. obs = "";
  58. myFunctions.rescan = function(lev) {
  59. var ari = $("chess-board")
  60. .find(".piece")
  61. .map(function() {
  62. return this.className;
  63. })
  64. .get();
  65. jack = ari.map(f => f.substring(f.indexOf(' ') + 1));
  66. function removeWord(arr, word) {
  67. for (var i = 0; i < arr.length; i++) {
  68. arr[i] = arr[i].replace(word, '');
  69. }
  70. }
  71. removeWord(ari, 'square-');
  72. jack = ari.map(f => f.substring(f.indexOf(' ') + 1));
  73. for (var i = 0; i < jack.length; i++) {
  74. jack[i] = jack[i].replace('br', 'r')
  75. .replace('bn', 'n')
  76. .replace('bb', 'b')
  77. .replace('bq', 'q')
  78. .replace('bk', 'k')
  79. .replace('bb', 'b')
  80. .replace('bn', 'n')
  81. .replace('br', 'r')
  82. .replace('bp', 'p')
  83. .replace('wp', 'P')
  84. .replace('wr', 'R')
  85. .replace('wn', 'N')
  86. .replace('wb', 'B')
  87. .replace('br', 'R')
  88. .replace('wn', 'N')
  89. .replace('wb', 'B')
  90. .replace('wq', 'Q')
  91. .replace('wk', 'K')
  92. .replace('wb', 'B')
  93. }
  94. str2 = "";
  95. var count = 0,
  96. str = "";
  97. for (var j = 8; j > 0; j--) {
  98. for (var i = 1; i < 9; i++) {
  99. (str = (jack.find(el => el.includes([i] + [j])))) ? str = str.replace(/[^a-zA-Z]+/g, ''): str = "";
  100. if (str == "") {
  101. count++;
  102. str = count.toString();
  103. if (!isNaN(str2.charAt(str2.length - 1))) str2 = str2.slice(0, -1);
  104. else {
  105. count = 1;
  106. str = count.toString()
  107. }
  108. }
  109. str2 += str;
  110. if (i == 8) {
  111. count = 0;
  112. str2 += "/";
  113. }
  114. }
  115. }
  116. str2 = str2.slice(0, -1);
  117. //str2=str2+" KQkq - 0"
  118. color = "";
  119. wk = wq = bk = bq = "0";
  120. const move = $('vertical-move-list')
  121. .children();
  122. if (move.length < 2) {
  123. stop_b = stop_w = s_br = s_br2 = s_wr = s_wr2 = 0;
  124. }
  125. if (stop_b != 1) {
  126. if (move.find(".black.node:contains('K')")
  127. .length) {
  128. bk = "";
  129. bq = "";
  130. stop_b = 1;
  131. console.log('debug secb');
  132. }
  133. } else {
  134. bq = "";
  135. bk = "";
  136. }
  137. if (stop_b != 1)(bk = (move.find(".black.node:contains('O-O'):not(:contains('O-O-O'))")
  138. .length) ? "" : "k") ? (bq = (move.find(".black.node:contains('O-O-O')")
  139. .length) ? bk = "" : "q") : bq = "";
  140. if (s_br != 1) {
  141. if (move.find(".black.node:contains('R')")
  142. .text()
  143. .match('[abcd]+')) {
  144. bq = "";
  145. s_br = 1
  146. }
  147. } else bq = "";
  148. if (s_br2 != 1) {
  149. if (move.find(".black.node:contains('R')")
  150. .text()
  151. .match('[hgf]+')) {
  152. bk = "";
  153. s_br2 = 1
  154. }
  155. } else bk = "";
  156. if (stop_b == 0) {
  157. if (s_br == 0)
  158. if (move.find(".white.node:contains('xa8')")
  159. .length > 0) {
  160. bq = "";
  161. s_br = 1;
  162. console.log('debug b castle_r');
  163. }
  164. if (s_br2 == 0)
  165. if (move.find(".white.node:contains('xh8')")
  166. .length > 0) {
  167. bk = "";
  168. s_br2 = 1;
  169. console.log('debug b castle_l');
  170. }
  171. }
  172. if (stop_w != 1) {
  173. if (move.find(".white.node:contains('K')")
  174. .length) {
  175. wk = "";
  176. wq = "";
  177. stop_w = 1;
  178. console.log('debug secw');
  179. }
  180. } else {
  181. wq = "";
  182. wk = "";
  183. }
  184. if (stop_w != 1)(wk = (move.find(".white.node:contains('O-O'):not(:contains('O-O-O'))")
  185. .length) ? "" : "K") ? (wq = (move.find(".white.node:contains('O-O-O')")
  186. .length) ? wk = "" : "Q") : wq = "";
  187. if (s_wr != 1) {
  188. if (move.find(".white.node:contains('R')")
  189. .text()
  190. .match('[abcd]+')) {
  191. wq = "";
  192. s_wr = 1
  193. }
  194. } else wq = "";
  195. if (s_wr2 != 1) {
  196. if (move.find(".white.node:contains('R')")
  197. .text()
  198. .match('[hgf]+')) {
  199. wk = "";
  200. s_wr2 = 1
  201. }
  202. } else wk = "";
  203. if (stop_w == 0) {
  204. if (s_wr == 0)
  205. if (move.find(".black.node:contains('xa1')")
  206. .length > 0) {
  207. wq = "";
  208. s_wr = 1;
  209. console.log('debug w castle_l');
  210. }
  211. if (s_wr2 == 0)
  212. if (move.find(".black.node:contains('xh1')")
  213. .length > 0) {
  214. wk = "";
  215. s_wr2 = 1;
  216. console.log('debug w castle_r');
  217. }
  218. }
  219. if ($('.coordinates')
  220. .children()
  221. .first()
  222. .text() == 1) {
  223. str2 = str2 + " b " + wk + wq + bk + bq;
  224. color = "white";
  225. } else {
  226. str2 = str2 + " w " + wk + wq + bk + bq;
  227. color = "black";
  228. }
  229. //console.log(str2);
  230. return str2;
  231. }
  232. myFunctions.color = function(dat){
  233. console.log("[Color Fn Input]:", dat);
  234. let bestmoveUCI = dat;
  235. if (typeof dat === 'string' && dat.startsWith('bestmove ')) {
  236. bestmoveUCI = dat.split(' ')[1];
  237. }
  238. console.log("[Color Fn Extracted UCI]:", bestmoveUCI);
  239. // Call highlight FIRST
  240. myFunctions.highlightMove(bestmoveUCI);
  241. // If autoMove is enabled, move the piece after a short delay
  242. if(myVars.autoMove == true){
  243. console.log("[Auto Move] Scheduling move in 50ms...");
  244. setTimeout(() => {
  245. myFunctions.movePiece(bestmoveUCI.substring(0, 2), bestmoveUCI.substring(2, 4));
  246. }, 50); // 50ms delay - adjust if needed
  247. }
  248. isThinking = false;
  249. }
  250.  
  251. // Simplified movePiece function based on Script 2
  252. myFunctions.movePiece = function(from, to){
  253. const uciMove = from + to;
  254. console.log("[Auto Move] Attempting move:", uciMove);
  255. if (!board || !board.game) {
  256. console.error("[Auto Move] Failed: Board or board.game not initialized!");
  257. return;
  258. }
  259. try {
  260. const legalMoves = board.game.getLegalMoves();
  261. const foundMove = legalMoves.find(move => move.from === from && move.to === to);
  262.  
  263. if (foundMove) {
  264. console.log("[Auto Move] Found legal move object:", foundMove);
  265. // Determine promotion piece (usually queen 'q')
  266. let promotion = undefined;
  267. const piece = board.game.getPiece(from);
  268. if (piece && piece.type === 'p' && (to[1] === '8' || to[1] === '1')) {
  269. promotion = 'q'; // Default promotion to Queen
  270. console.log("[Auto Move] Pawn promotion to Queen detected.");
  271. }
  272.  
  273. board.game.move({
  274. from: foundMove.from,
  275. to: foundMove.to,
  276. promotion: promotion, // Add promotion piece if needed
  277. animate: false, // Set to false for faster moves, true for visual effect
  278. userGenerated: true // Important to mimic user action
  279. });
  280. console.log("[Auto Move] Move executed via board.game.move:", uciMove);
  281. } else {
  282. console.warn("[Auto Move] Failed: No legal move found for UCI:", uciMove, "Available moves:", legalMoves);
  283. // Fallback to highlighting if move fails
  284. myFunctions.highlightMove(uciMove);
  285. }
  286. } catch (error) {
  287. console.error("[Auto Move] Error during move execution:", error);
  288. // Fallback to highlighting on error
  289. myFunctions.highlightMove(uciMove);
  290. }
  291. }
  292.  
  293. function parser(e){
  294. console.log("[Engine Raw]:", e.data); // Log raw engine output
  295. if(e.data.includes('bestmove')){
  296. console.log("[Engine Parsed Bestmove Line]:", e.data);
  297. myFunctions.color(e.data.split(' ')[1]);
  298. isThinking = false;
  299. }
  300. }
  301.  
  302. myFunctions.reloadChessEngine = function() {
  303. console.log(`Reloading the chess engine!`);
  304.  
  305. engine.engine.terminate();
  306. isThinking = false;
  307. myFunctions.loadChessEngine();
  308. }
  309.  
  310. myFunctions.loadChessEngine = function() {
  311. if(!stockfishObjectURL) {
  312. stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
  313. }
  314. console.log(stockfishObjectURL);
  315. if(stockfishObjectURL) {
  316. engine.engine = new Worker(stockfishObjectURL);
  317.  
  318. engine.engine.onmessage = e => {
  319. parser(e);
  320. };
  321. engine.engine.onerror = e => {
  322. console.log("Worker Error: "+e);
  323. };
  324.  
  325. engine.engine.postMessage('ucinewgame');
  326. }
  327. console.log('loaded chess engine');
  328. }
  329.  
  330. var lastValue = 11;
  331. myFunctions.runChessEngine = function(depth){
  332. var fen = board.game.getFEN();
  333. console.log(`[Engine Send] Position FEN: ${fen}`); // Log FEN being sent
  334. console.log(`[Engine Send] Go Depth: ${depth}`); // Log depth
  335. engine.engine.postMessage(`position fen ${fen}`);
  336. console.log('updated: ' + `position fen ${fen}`);
  337. isThinking = true;
  338. engine.engine.postMessage(`go depth ${depth}`);
  339. lastValue = depth;
  340. }
  341.  
  342. myFunctions.autoRun = function(){
  343. if(board.game.getTurn() == board.game.getPlayingAs()){
  344. myFunctions.runChessEngine(myVars.customDepth);
  345. }
  346. }
  347.  
  348. document.onkeydown = function(e) {
  349. let depthToRun = -1;
  350. switch (e.keyCode) {
  351. case 81: depthToRun = 1; break;
  352. case 87: depthToRun = 2; break;
  353. case 69: depthToRun = 3; break;
  354. case 82: depthToRun = 4; break;
  355. case 84: depthToRun = 5; break;
  356. case 89: depthToRun = 6; break;
  357. case 85: depthToRun = 7; break;
  358. case 73: depthToRun = 8; break;
  359. case 79: depthToRun = 9; break;
  360. case 80: depthToRun = 10; break;
  361. case 65: depthToRun = 11; break;
  362. case 83: depthToRun = 12; break;
  363. case 68: depthToRun = 13; break;
  364. case 70: depthToRun = 14; break;
  365. case 71: depthToRun = 15; break;
  366. case 72: depthToRun = 16; break;
  367. case 74: depthToRun = 17; break;
  368. case 75: depthToRun = 18; break;
  369. case 76: depthToRun = 19; break;
  370. case 90: depthToRun = 20; break;
  371. case 88: depthToRun = 21; break;
  372. case 67: depthToRun = 22; break;
  373. case 86: depthToRun = 23; break;
  374. case 66: depthToRun = 24; break;
  375. case 78: depthToRun = 25; break;
  376. case 77: depthToRun = 26; break;
  377. case 187: depthToRun = 100; break; // '+' key
  378. }
  379.  
  380. // Handle depth setting via keys Q-M and +
  381. if (depthToRun !== -1) {
  382. myVars.customDepth = depthToRun; // Update the stored depth
  383. if (loaded) {
  384. $('#customDepthInput').val(myVars.customDepth);
  385. $('#depthText')[0].innerHTML = "Current Depth: <strong>" + myVars.customDepth + "</strong>";
  386. }
  387. myFunctions.runChessEngine(myVars.customDepth);
  388. }
  389. // Handle UI Toggle via ESC key
  390. if (e.keyCode === 27) { // ESC key
  391. if (loaded) {
  392. const panel = $('#settingsContainer');
  393. if (panel.length > 0) {
  394. panel.toggle(); // Toggle visibility
  395. console.log("Toggled UI panel visibility.");
  396. }
  397. }
  398. }
  399. };
  400.  
  401. myFunctions.spinner = function() {
  402. if (loaded && $('#overlay').length > 0) {
  403. $('#overlay').css('display', isThinking ? 'block' : 'none');
  404. } else if (loaded) {
  405. console.warn("Spinner overlay #overlay not found.");
  406. }
  407. }
  408.  
  409. let dynamicStyles = null;
  410.  
  411. function addAnimation(body) {
  412. if (!dynamicStyles) {
  413. dynamicStyles = document.createElement('style');
  414. dynamicStyles.type = 'text/css';
  415. document.head.appendChild(dynamicStyles);
  416. }
  417.  
  418. dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
  419. }
  420.  
  421.  
  422. myFunctions.replaceAd = function(){
  423. // Removed ad replacement logic
  424. }
  425.  
  426. var loaded = false;
  427. myFunctions.loadEx = function(){
  428. if (loaded) return; // Prevent re-loading
  429. try{
  430. console.log("Loading UI panel (Step 1)... ");
  431. board = $('chess-board')[0] || $('wc-chess-board')[0];
  432. if (!board) {
  433. console.warn("Cannot load UI - board element not found yet.");
  434. return; // Don't proceed if board isn't there
  435. }
  436. myVars.board = board;
  437.  
  438. // --- Inject Styles ---
  439. myFunctions.injectStyles();
  440.  
  441. // --- Create Panel ---
  442. // Remove any old panel first (if reloading during testing)
  443. $('#settingsContainer').remove();
  444. // Create the main panel div
  445. const $panel = $('<div>').attr('id', 'settingsContainer');
  446.  
  447. // --- Spinner ---
  448. const $spinnerOverlay = $('<div>').attr('id', 'overlay').hide(); // Start hidden
  449. const $spinner = $('<div>'); // The actual spinner div (styled by CSS)
  450. $spinnerOverlay.append($spinner);
  451. $panel.append($spinnerOverlay);
  452.  
  453. // --- Depth Section ---
  454. $panel.append('<h3>Engine Depth</h3>');
  455. const $depthDiv = $('<div>');
  456. $depthDiv.append(
  457. $('<span>').attr('id', 'depthText').html(`Current: <strong>${myVars.customDepth}</strong>`)
  458. );
  459. $depthDiv.append('<br>'); // Line break
  460. $depthDiv.append($('<label>').attr('for', 'customDepthInput').text('Set Depth:'));
  461. const $depthInput = $('<input>').attr({
  462. type: 'number', id: 'customDepthInput', name: 'customDepthInput',
  463. min: '1', max: '100', value: myVars.customDepth
  464. });
  465. $depthDiv.append($depthInput);
  466. $panel.append($depthDiv);
  467.  
  468. // --- Game Options Section ---
  469. $panel.append('<h3>Game Options</h3>');
  470. const $optionsDiv = $('<div>');
  471. // Auto Run
  472. $optionsDiv.append(
  473. $('<div>').addClass('options-line').append(
  474. $('<input>').attr({ type: 'checkbox', id: 'autoRun', name: 'autoRun', checked: myVars.autoRun }),
  475. $('<label>').attr('for', 'autoRun').addClass('inline').text('Enable auto run')
  476. )
  477. );
  478. // Auto Move
  479. $optionsDiv.append(
  480. $('<div>').addClass('options-line').append(
  481. $('<input>').attr({ type: 'checkbox', id: 'autoMove', name: 'autoMove', checked: myVars.autoMove }),
  482. $('<label>').attr('for', 'autoMove').addClass('inline').text('Enable auto move')
  483. )
  484. );
  485. // Auto Match
  486. $optionsDiv.append(
  487. $('<div>').addClass('options-line').append(
  488. $('<input>').attr({ type: 'checkbox', id: 'autoMatch', name: 'autoMatch', checked: myVars.autoMatch }),
  489. $('<label>').attr('for', 'autoMatch').addClass('inline').text('Enable auto match')
  490. )
  491. );
  492. $panel.append($optionsDiv);
  493.  
  494. // --- Delay Section ---
  495. $panel.append('<h3>Auto Run Delay</h3>');
  496. const $delayDiv = $('<div>');
  497. $delayDiv.append(
  498. $('<div>').addClass('options-line').append( // Wrap in div for spacing
  499. $('<label>').attr('for', 'timeDelayMin').text('Min (s):'),
  500. $('<input>').attr({ type: 'number', id: 'timeDelayMin', name: 'timeDelayMin', min: '0.1', step: '0.1', value: GM_getValue('delayMin', 0.1) })
  501. )
  502. );
  503. $delayDiv.append(
  504. $('<div>').addClass('options-line').append(
  505. $('<label>').attr('for', 'timeDelayMax').text('Max (s):'),
  506. $('<input>').attr({ type: 'number', id: 'timeDelayMax', name: 'timeDelayMax', min: '0.1', step: '0.1', value: GM_getValue('delayMax', 1.0) })
  507. )
  508. );
  509. $panel.append($delayDiv);
  510.  
  511. // --- Display Section ---
  512. $panel.append('<h3>Display</h3>');
  513. const $displayDiv = $('<div>').addClass('options-line'); // Use options-line for consistency
  514. $displayDiv.append(
  515. $('<label>').attr('for', 'highlightColorInput').text('Highlight Color:'),
  516. $('<input>').attr({ type: 'color', id: 'highlightColorInput', name: 'highlightColorInput', value: myVars.bestMoveHighlightColor })
  517. );
  518. $panel.append($displayDiv);
  519.  
  520. // --- Buttons Section ---
  521. $panel.append('<h3>Actions</h3>');
  522. // Reload Button
  523. const $reloadButton = $('<button>').attr({ type: 'button', name: 'reloadEngine', id: 'relEngBut' })
  524. .text('Reload Chess Engine');
  525. $panel.append($reloadButton);
  526. // Issue Button
  527. const $issueButton = $('<button>').attr({ type: 'button', name: 'isBut', id: 'isBut' })
  528. .text('Report an issue?');
  529. $panel.append($issueButton);
  530. // Update Button
  531. const $updateButton = $('<button>').attr({ type: 'button', id: 'updateScriptButton' })
  532. .text('Check for Updates');
  533. $panel.append($updateButton);
  534.  
  535. // --- Append Panel to Body ---
  536. $('body').append($panel); // Append to body for fixed positioning
  537.  
  538. // --- Attach Depth Event Listener ---
  539. $panel.find('#customDepthInput').on('change', function() {
  540. const newDepth = parseInt($(this).val(), 10);
  541. if (!isNaN(newDepth) && newDepth >= 1 && newDepth <= 100) {
  542. myVars.customDepth = newDepth;
  543. $panel.find('#depthText').html(`Current: <strong>${myVars.customDepth}</strong>`);
  544. } else {
  545. $(this).val(myVars.customDepth); // Reset invalid input
  546. }
  547. });
  548.  
  549. // --- Attach Checkbox Event Listeners ---
  550. $panel.find('#autoRun').on('change', function() { myVars.autoRun = $(this).is(':checked'); console.log(`[Event] autoRun changed to: ${myVars.autoRun}`); });
  551. $panel.find('#autoMove').on('change', function() { myVars.autoMove = $(this).is(':checked'); console.log(`[Event] autoMove changed to: ${myVars.autoMove}`); });
  552. $panel.find('#autoMatch').on('change', function() { myVars.autoMatch = $(this).is(':checked'); console.log(`[Event] autoMatch changed to: ${myVars.autoMatch}`); });
  553.  
  554. // --- Attach Delay Input Event Listeners ---
  555. $panel.find('#timeDelayMin').on('change', function() {
  556. let minVal = parseFloat($(this).val());
  557. let maxVal = parseFloat($panel.find('#timeDelayMax').val());
  558. if (isNaN(minVal) || minVal < 0.1) minVal = 0.1;
  559. if (minVal > maxVal) minVal = maxVal; // Prevent min > max
  560. $(this).val(minVal.toFixed(1)); // Update potentially corrected value
  561. GM_setValue('delayMin', minVal);
  562. myVars.delayMin = minVal; // Update runtime var
  563. console.log(`[Event] Delay Min changed to: ${minVal}`);
  564. });
  565. $panel.find('#timeDelayMax').on('change', function() {
  566. let maxVal = parseFloat($(this).val());
  567. let minVal = parseFloat($panel.find('#timeDelayMin').val());
  568. if (isNaN(maxVal) || maxVal < 0.1) maxVal = 0.1;
  569. if (maxVal < minVal) maxVal = minVal; // Prevent max < min
  570. $(this).val(maxVal.toFixed(1)); // Update potentially corrected value
  571. GM_setValue('delayMax', maxVal);
  572. myVars.delayMax = maxVal; // Update runtime var
  573. console.log(`[Event] Delay Max changed to: ${maxVal}`);
  574. });
  575.  
  576. // --- Attach Color Picker Event Listener ---
  577. $panel.find('#highlightColorInput').on('change', function() {
  578. myVars.bestMoveHighlightColor = $(this).val();
  579. GM_setValue('bestMoveHighlightColor', myVars.bestMoveHighlightColor);
  580. console.log(`[Event] Highlight color changed to: ${myVars.bestMoveHighlightColor}`);
  581. });
  582.  
  583. // --- Attach Button Event Listeners ---
  584. $panel.find('#relEngBut').on('click', myFunctions.reloadChessEngine);
  585. $panel.find('#isBut').on('click', () => { window.confirm('Report an issue? (External link)') ? document.location = 'mailto:example@example.com' : console.log('Issue report canceled.'); });
  586. $panel.find('#updateScriptButton').on('click', () => {
  587. const scriptPageURL = 'https://greatest.deepsurf.us/en/scripts/534105-chess-com-bot-cheat-by-admin0'; // Your script's page
  588. window.open(scriptPageURL, '_blank');
  589. console.log('Opened script page for update check:', scriptPageURL);
  590. });
  591.  
  592. // Initialize runtime delay vars from saved values
  593. myVars.delayMin = parseFloat($panel.find('#timeDelayMin').val());
  594. myVars.delayMax = parseFloat($panel.find('#timeDelayMax').val());
  595.  
  596. loaded = true;
  597. console.log("UI Panel Created Successfully (Step 1).");
  598.  
  599. } catch (error) {
  600. console.error("Error loading UI (Step 1):", error);
  601. loaded = false; // Ensure it tries again if error occurs
  602. }
  603. }
  604.  
  605. // Function to inject CSS styles for the UI panel
  606. myFunctions.injectStyles = function() {
  607. // Basic panel styles - positioning and colors
  608. const css = `
  609. #settingsContainer {
  610. position: fixed;
  611. right: 10px;
  612. top: 50%;
  613. transform: translateY(-50%);
  614. width: 260px; /* Back to standard width */
  615. max-height: 85vh;
  616. overflow-y: auto;
  617. background-color: #312e2b; /* Standard Chess.com dark bg */
  618. color: #cccccc; /* Standard light text */
  619. border: 1px solid #444; /* Standard border */
  620. border-radius: 6px; /* Standard radius */
  621. padding: 10px 15px; /* Standard padding */
  622. font-family: "Noto Sans", sans-serif;
  623. font-size: 14px;
  624. z-index: 9999;
  625. box-shadow: 0 4px 12px rgba(0,0,0,0.5); /* Standard shadow */
  626. user-select: none;
  627. transition: box-shadow 0.3s ease;
  628. }
  629. #settingsContainer:hover {
  630. box-shadow: 0 6px 18px rgba(0,0,0,0.6); /* Standard subtle hover */
  631. /* Remove scale effect */
  632. }
  633.  
  634. /* Spinner adjustments */
  635. #overlay {
  636. position: absolute;
  637. top: 0; left: 0; right: 0; bottom: 0;
  638. background-color: rgba(49, 46, 43, 0.75); /* Match bg */
  639. z-index: 10000;
  640. display: none;
  641. border-radius: 6px; /* Match panel */
  642. }
  643. #overlay > div {
  644. position: absolute;
  645. top: 50%; left: 50%;
  646. height: 40px; width: 40px;
  647. margin-top: -20px; margin-left: -20px;
  648. border: 4px solid #888; /* Standard grey spinner */
  649. border-right-color: transparent;
  650. border-radius: 50%;
  651. animation: rotate 0.8s infinite linear;
  652. }
  653.  
  654. /* Section Headings */
  655. #settingsContainer h3 {
  656. color: #ededed; /* Standard heading color */
  657. margin-top: 15px;
  658. margin-bottom: 10px;
  659. padding-bottom: 5px;
  660. border-bottom: 1px solid #444; /* Standard separator */
  661. font-size: 16px;
  662. font-weight: bold;
  663. letter-spacing: normal; /* Standard spacing */
  664. }
  665. #settingsContainer h3:first-of-type {
  666. margin-top: 0;
  667. }
  668.  
  669. /* Input Styling */
  670. #settingsContainer label {
  671. display: block;
  672. margin-bottom: 3px;
  673. color: #cccccc; /* Standard label color */
  674. cursor: default;
  675. }
  676. #settingsContainer input[type="number"],
  677. #settingsContainer input[type="color"] {
  678. background-color: #444; /* Standard input bg */
  679. border: 1px solid #555; /* Standard input border */
  680. color: #ccc;
  681. padding: 5px;
  682. border-radius: 3px;
  683. margin-left: 5px;
  684. vertical-align: middle;
  685. }
  686. #settingsContainer input[type="number"] {
  687. width: 55px;
  688. }
  689. #settingsContainer input[type="color"] {
  690. width: 40px;
  691. height: 25px;
  692. padding: 1px;
  693. cursor: pointer;
  694. border-color: #555; /* Standard border */
  695. }
  696.  
  697. /* Checkbox/Inline Label Styling */
  698. #settingsContainer label.inline {
  699. display: inline-block;
  700. margin-left: 5px;
  701. margin-bottom: 0;
  702. vertical-align: middle;
  703. font-weight: normal;
  704. color: #cccccc; /* Standard text color */
  705. cursor: pointer;
  706. }
  707. #settingsContainer input[type="checkbox"] {
  708. margin-right: 5px;
  709. vertical-align: middle;
  710. cursor: pointer;
  711. /* Revert to default checkbox appearance for better theme consistency */
  712. appearance: checkbox;
  713. background-color: initial;
  714. border: initial;
  715. width: auto;
  716. height: auto;
  717. border-radius: initial;
  718. position: relative;
  719. top: 0; /* Reset alignment */
  720. }
  721. /* Remove custom checked styles */
  722. /* #settingsContainer input[type="checkbox"]:checked { ... } */
  723. /* #settingsContainer input[type="checkbox"]:checked::after { ... } */
  724.  
  725. #settingsContainer div.options-line {
  726. margin-bottom: 8px;
  727. padding: 4px 6px;
  728. border-radius: 4px;
  729. transition: background-color 0.2s ease;
  730. }
  731. #settingsContainer div.options-line:hover {
  732. background-color: #3c3936; /* Subtle hover */
  733. cursor: default;
  734. }
  735.  
  736. /* Button Styling */
  737. #settingsContainer button {
  738. display: block;
  739. width: 100%;
  740. box-sizing: border-box;
  741. text-align: center;
  742. background-color: #81b64c; /* Adjusted Chess.com green */
  743. color: white;
  744. border: none;
  745. border-radius: 4px;
  746. padding: 8px 10px;
  747. margin-top: 10px;
  748. font-size: 14px;
  749. font-weight: bold;
  750. cursor: pointer;
  751. text-shadow: none;
  752. transition: background-color 0.2s ease;
  753. }
  754. #settingsContainer button:hover {
  755. background-color: #93cc5b; /* Lighter green for hover */
  756. box-shadow: none;
  757. transform: none;
  758. }
  759. #settingsContainer button:active {
  760. transform: none;
  761. box-shadow: none;
  762. background-color: #70a140; /* Darker green for active */
  763. }
  764.  
  765. #settingsContainer button#isBut { /* Secondary Button */
  766. background-color: #555;
  767. margin-top: 5px;
  768. }
  769. #settingsContainer button#isBut:hover {
  770. background-color: #666;
  771. box-shadow: none;
  772. transform: none;
  773. }
  774. #settingsContainer button#isBut:active {
  775. transform: none;
  776. box-shadow: none;
  777. background-color: #4a4a4a;
  778. }
  779. `;
  780. const styleSheet = document.createElement("style");
  781. styleSheet.type = "text/css";
  782. styleSheet.innerText = css;
  783. document.head.appendChild(styleSheet);
  784. console.log("Injected basic bot UI styles.");
  785. }
  786.  
  787. function other(delay){
  788. var endTime = Date.now() + delay;
  789. var timer = setInterval(()=>{
  790. if(Date.now() >= endTime){
  791. myFunctions.autoRun();
  792. canGo = true;
  793. clearInterval(timer);
  794. }
  795. },10);
  796. }
  797.  
  798.  
  799. async function getVersion(){
  800. var GF = new GreasyFork; // set upping api
  801. var code = await GF.get().script().code(460208); // Get code
  802. var version = GF.parseScriptCodeMeta(code).filter(e => e.meta === '@version')[0].value; // filtering array and getting value of @version
  803.  
  804. if(currentVersion !== version){
  805. while(true){
  806. alert('UPDATE THIS SCRIPT IN ORDER TO PROCEED!');
  807. }
  808. }
  809. }
  810.  
  811. //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.
  812. //getVersion();
  813.  
  814. const waitForChessBoard = setInterval(() => {
  815. if(loaded) {
  816. board = $('chess-board')[0] || $('wc-chess-board')[0];
  817.  
  818. // Read delay values from myVars (set by event listeners or initial load)
  819. let minDel = myVars.delayMin || 0.1;
  820. let maxDel = myVars.delayMax || 1.0;
  821. // No need to check min > max here, listener handles it
  822. // Recalculate random delay for this interval check
  823. myVars.delay = Math.random() * (maxDel - minDel) + minDel;
  824.  
  825. myVars.isThinking = isThinking;
  826. myFunctions.spinner();
  827.  
  828. // Check if game has ended by looking for the game over modal
  829. const gameOverModal = $('.game-over-modal-content');
  830. if (gameOverModal.length > 0 && !myVars.gameEnded) {
  831. console.log("Game over detected.");
  832. myVars.gameEnded = true;
  833. myVars.hasAutoMatched = false; // Reset auto-match flag for the new game opportunity
  834. }
  835.  
  836. // Determine whose turn it is, ONLY if the game hasn't ended
  837. if (!myVars.gameEnded && board && board.game) { // Check !myVars.gameEnded here
  838. try {
  839. myTurn = (board.game.getTurn() == board.game.getPlayingAs());
  840. } catch (e) {
  841. console.warn("[Turn Check] Error getting turn/playingAs:", e);
  842. myTurn = false;
  843. }
  844. } else {
  845. myTurn = false; // Not my turn if game ended or board not ready
  846. }
  847.  
  848. } else if ($('chess-board, wc-chess-board').length > 0 && !$('#settingsContainer').length) { // Try to load if board exists and panel doesn't
  849. myFunctions.loadEx(); // Try loading UI if not loaded
  850. }
  851.  
  852. // --- Logic Execution Section ---
  853.  
  854. // Log current state before checks
  855. if (loaded && board && board.game) { // Only log if things are loaded
  856. console.log(`[State Check] AutoRun:${myVars.autoRun} AutoMove:${myVars.autoMove} AutoMatch:${myVars.autoMatch} MyTurn:${myTurn} GameEnded:${myVars.gameEnded} Thinking:${isThinking} CanGo:${canGo} HasAutoMatched:${myVars.hasAutoMatched}`);
  857. try {
  858. // Also log board.game state if possible
  859. console.log(`[Board Check] Turn: ${board.game.getTurn()}, PlayingAs: ${board.game.getPlayingAs()}, FEN: ${board.game.getFEN()}`);
  860. // Add specific turn/playingAs log
  861. console.log(`[Board Check] getPlayingAs(): ${board.game.getPlayingAs()}, getTurn(): ${board.game.getTurn()}`);
  862. } catch (e) {
  863. console.warn("[Board Check] Error getting board.game details:", e);
  864. }
  865. }
  866.  
  867. // Auto Run Logic
  868. if(myVars.autoRun == true && canGo == true && isThinking == false && myTurn && !myVars.gameEnded){
  869. console.log("[Action] Triggering Auto Run..."); // Log trigger
  870. canGo = false;
  871. var currentDelay = myVars.delay != undefined ? myVars.delay * 1000 : 10;
  872. other(currentDelay); // Call other without depth parameter
  873. }
  874.  
  875. // Auto Match Logic
  876. if (myVars.autoMatch && myVars.gameEnded && !myVars.hasAutoMatched && !myVars.isAttemptingAutoMatch) {
  877. console.log("[Action] Triggering Auto Match Sequence..."); // Updated log
  878. myFunctions.startNewGame();
  879. // Note: startNewGame now sets flags and manages its own state
  880. }
  881.  
  882. }, 100); // Interval runs every 100ms
  883.  
  884. myFunctions.startNewGame = function() {
  885. console.log("Starting new game..."); // Log from Script 2 version
  886. const modalNewGameButton = $('.game-over-modal-content .game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  887. if (modalNewGameButton.length) {
  888. modalNewGameButton[0].click();
  889. console.log("Clicked New <x> min button from game-over modal.");
  890. myVars.hasAutoMatched = true;
  891. myVars.gameEnded = false; // Reset flag
  892. myVars.isAttemptingAutoMatch = false; // Reset flag
  893. return;
  894. }
  895. const newGameButton = $('.game-over-buttons-component .cc-button-component:not([aria-label="Rematch"])');
  896. if (newGameButton.length) {
  897. newGameButton[0].click();
  898. console.log("Clicked New <x> min button from game-over.");
  899. myVars.hasAutoMatched = true;
  900. myVars.gameEnded = false; // Reset flag
  901. myVars.isAttemptingAutoMatch = false; // Reset flag
  902. return;
  903. }
  904. const guestButton = $('#guest-button.authentication-intro-guest');
  905. if (guestButton.length) {
  906. guestButton[0].click();
  907. console.log("Clicked Play as Guest.");
  908. setTimeout(() => {
  909. const playButton = $('.cc-button-component.cc-button-primary.cc-button-xx-large.cc-button-full');
  910. if (playButton.length) {
  911. playButton[0].click();
  912. console.log("Clicked Play button after guest prompt.");
  913. myVars.hasAutoMatched = true;
  914. myVars.gameEnded = false; // Reset flag
  915. myVars.isAttemptingAutoMatch = false; // Reset flag
  916. } else {
  917. console.error("Play button not found after guest prompt!");
  918. myVars.isAttemptingAutoMatch = false; // Reset flag even on failure
  919. }
  920. }, 500);
  921. return; // Return after starting timeout
  922. }
  923. const newGameTab = $('[data-tab="newGame"]');
  924. if (newGameTab.length) {
  925. newGameTab[0].click();
  926. console.log("Clicked New Game tab.");
  927. setTimeout(() => {
  928. const playButton = $('.cc-button-component.cc-button-primary.cc-button-xx-large.cc-button-full');
  929. if (playButton.length) {
  930. playButton[0].click();
  931. console.log("Clicked Play button.");
  932. myVars.hasAutoMatched = true;
  933. myVars.gameEnded = false; // Reset flag
  934. myVars.isAttemptingAutoMatch = false; // Reset flag
  935. } else {
  936. console.error("Play button not found after clicking New Game tab!");
  937. myVars.isAttemptingAutoMatch = false; // Reset flag even on failure
  938. }
  939. }, 500);
  940. return; // Return after starting timeout
  941. }
  942.  
  943. // If no buttons were found and clicked
  944. console.error("No suitable New Game button/tab found by Script 2 logic.");
  945. myVars.isAttemptingAutoMatch = false; // Reset flag if nothing found
  946. };
  947.  
  948. myFunctions.highlightMove = function(bestmoveUCI) {
  949. // Remove previous highlights first
  950. $('.highlight.bro').remove();
  951.  
  952. console.log(`[Highlight] Received UCI: ${bestmoveUCI}, Length: ${bestmoveUCI?.length}`); // Log input
  953.  
  954. if (!bestmoveUCI || bestmoveUCI.length < 4) {
  955. console.error("[Highlight] Invalid UCI string received:", bestmoveUCI);
  956. return; // Don't proceed if UCI is bad
  957. }
  958.  
  959. let res1 = bestmoveUCI.substring(0, 2);
  960. let res2 = bestmoveUCI.substring(2, 4);
  961. const highlightColor = myVars.bestMoveHighlightColor || '#EB6150';
  962.  
  963. // --- Add coordinate translation --- START
  964. function translateCoords(uciSquare) {
  965. return uciSquare
  966. .replace(/^a/, "1")
  967. .replace(/^b/, "2")
  968. .replace(/^c/, "3")
  969. .replace(/^d/, "4")
  970. .replace(/^e/, "5")
  971. .replace(/^f/, "6")
  972. .replace(/^g/, "7")
  973. .replace(/^h/, "8");
  974. }
  975. const translatedSq1 = translateCoords(res1);
  976. const translatedSq2 = translateCoords(res2);
  977. console.log(`[Highlight] Translated: ${res1} -> ${translatedSq1}, ${res2} -> ${translatedSq2}`);
  978. // --- Add coordinate translation --- END
  979. try {
  980. console.log(`[Highlight] Highlighting TO square: ${translatedSq2}`);
  981. $(board.nodeName) // Use board.nodeName to be safe
  982. .prepend(`<div class="highlight square-${translatedSq2} bro" style="background-color: ${highlightColor}; opacity: 0.71; pointer-events: none;" data-test-element="highlight"></div>`)
  983. .children(':first')
  984. .delay(1800)
  985. .queue(function() { $(this).remove(); });
  986. } catch (e) {
  987. console.error(`[Highlight] Error highlighting TO square ${translatedSq2}:`, e);
  988. }
  989. try {
  990. console.log(`[Highlight] Highlighting FROM square: ${translatedSq1}`);
  991. $(board.nodeName)
  992. .prepend(`<div class="highlight square-${translatedSq1} bro" style="background-color: ${highlightColor}; opacity: 0.71; pointer-events: none;" data-test-element="highlight"></div>`)
  993. .children(':first')
  994. .delay(1800)
  995. .queue(function() { $(this).remove(); });
  996. } catch (e) {
  997. console.error(`[Highlight] Error highlighting FROM square ${translatedSq1}:`, e);
  998. }
  999.  
  1000. console.log("[Highlight] Finished highlighting.");
  1001. }
  1002.  
  1003. myFunctions.highlightThreats = function() {
  1004. // Placeholder for the removed highlightThreats function
  1005. };
  1006. }
  1007.  
  1008. //Touching below may break the script
  1009.  
  1010. var isThinking = false
  1011. var canGo = true;
  1012. var myTurn = false;
  1013. var board;
  1014.  
  1015. window.addEventListener("load", (event) => {
  1016. main();
  1017. });