Greasy Fork is available in English.

Chess.com UltraX bot with Panel

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.

2025-03-29 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

  1. // ==UserScript==
  2. // additional copyright/license info:
  3. //© All Rights Reserved
  4. //
  5. //Chess.com Enhanced Experience © 2024 by Akashdeep
  6. //
  7. // ==UserScript
  8. // @name Chess.com UltraX bot with Panel
  9. // @namespace Akashdeep
  10. // @version 1.0.0.5
  11. // @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.
  12. // @author Akashdeep
  13. // @license Chess.com Enhanced Experience © 2024 by Akashdeep, © All Rights Reserved
  14. // @match https://www.chess.com/play/*
  15. // @match https://www.chess.com/game/*
  16. // @match https://www.chess.com/puzzles/*
  17. // @match https://www.chess.com/*
  18. // @icon data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  19. // @grant GM_getValue
  20. // @grant GM_setValue
  21. // @grant GM_xmlhttpRequest
  22. // @grant GM_getResourceText
  23. // @grant GM_registerMenuCommand
  24. // @resource stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.2/stockfish.js
  25. // @require https://greatest.deepsurf.us/scripts/445697/code/index.js
  26. // @require https://code.jquery.com/jquery-3.6.0.min.js
  27. // @run-at document-start
  28. // @liscense MIT
  29.  
  30. // @downloadURL
  31. // @updateURL
  32. // ==/UserScript==
  33.  
  34. //Don't touch anything below unless you know what your doing!
  35.  
  36. const currentVersion = '1.0.0.5'; // Sets the current version
  37.  
  38. function main() {
  39.  
  40. var stockfishObjectURL;
  41. var engine = document.engine = {};
  42. var myVars = document.myVars = {};
  43. myVars.autoMovePiece = false;
  44. myVars.autoRun = false;
  45. myVars.delay = 0.1;
  46. var myFunctions = document.myFunctions = {};
  47.  
  48. myVars.playStyle = {
  49. aggressive: Math.random() * 0.5 + 0.3, // 0.3-0.8 tendency for aggressive moves
  50. defensive: Math.random() * 0.5 + 0.3, // 0.3-0.8 tendency for defensive moves
  51. tactical: Math.random() * 0.6 + 0.2, // 0.2-0.8 tendency for tactical moves
  52. positional: Math.random() * 0.6 + 0.2 // 0.2-0.8 tendency for positional moves
  53. };
  54.  
  55. myVars.preferredOpenings = [
  56. "e4", "d4", "c4", "Nf3" // Just examples, could be expanded
  57. ].sort(() => Math.random() - 0.5); // Randomize the order
  58.  
  59. myVars.playerFingerprint = GM_getValue('playerFingerprint', {
  60. favoredPieces: Math.random() < 0.5 ? 'knights' : 'bishops',
  61. openingTempo: Math.random() * 0.5 + 0.5, // 0.5-1.0 opening move speed
  62. tacticalAwareness: Math.random() * 0.4 + 0.6, // 0.6-1.0 tactical vision
  63. exchangeThreshold: Math.random() * 0.3 + 0.1, // When to accept exchanges
  64. attackingStyle: ['kingside', 'queenside', 'central'][Math.floor(Math.random() * 3)]
  65. });
  66. // Save on first run
  67. if (!GM_getValue('playerFingerprint')) {
  68. GM_setValue('playerFingerprint', myVars.playerFingerprint);
  69. }
  70.  
  71. // Add to myVars initialization
  72. myVars.tacticalProfile = GM_getValue('tacticalProfile', {
  73. strengths: [
  74. getRandomTacticalStrength(),
  75. getRandomTacticalStrength()
  76. ],
  77. weaknesses: [
  78. getRandomTacticalWeakness(),
  79. getRandomTacticalWeakness()
  80. ]
  81. });
  82.  
  83. // Save on first run
  84. if (!GM_getValue('tacticalProfile')) {
  85. GM_setValue('tacticalProfile', myVars.tacticalProfile);
  86. }
  87.  
  88. function getRandomTacticalStrength() {
  89. const strengths = [
  90. 'fork', 'pin', 'skewer', 'discovery', 'zwischenzug',
  91. 'removing-defender', 'attraction'
  92. ];
  93. return strengths[Math.floor(Math.random() * strengths.length)];
  94. }
  95.  
  96. function getRandomTacticalWeakness() {
  97. const weaknesses = [
  98. 'long-calculation', 'quiet-moves', 'backward-moves',
  99. 'zugzwang', 'prophylaxis', 'piece-coordination'
  100. ];
  101. return weaknesses[Math.floor(Math.random() * weaknesses.length)];
  102. }
  103.  
  104. stop_b = stop_w = 0;
  105. s_br = s_br2 = s_wr = s_wr2 = 0;
  106. obs = "";
  107. myFunctions.rescan = function(lev) {
  108. var ari = $("chess-board")
  109. .find(".piece")
  110. .map(function() {
  111. return this.className;
  112. })
  113. .get();
  114. jack = ari.map(f => f.substring(f.indexOf(' ') + 1));
  115. function removeWord(arr, word) {
  116. for (var i = 0; i < arr.length; i++) {
  117. arr[i] = arr[i].replace(word, '');
  118. }
  119. }
  120. removeWord(ari, 'square-');
  121. jack = ari.map(f => f.substring(f.indexOf(' ') + 1));
  122. for (var i = 0; i < jack.length; i++) {
  123. jack[i] = jack[i].replace('br', 'r')
  124. .replace('bn', 'n')
  125. .replace('bb', 'b')
  126. .replace('bq', 'q')
  127. .replace('bk', 'k')
  128. .replace('bb', 'b')
  129. .replace('bn', 'n')
  130. .replace('br', 'r')
  131. .replace('bp', 'p')
  132. .replace('wp', 'P')
  133. .replace('wr', 'R')
  134. .replace('wn', 'N')
  135. .replace('wb', 'B')
  136. .replace('br', 'R')
  137. .replace('wn', 'N')
  138. .replace('wb', 'B')
  139. .replace('wq', 'Q')
  140. .replace('wk', 'K')
  141. .replace('wb', 'B')
  142. }
  143. str2 = "";
  144. var count = 0,
  145. str = "";
  146. for (var j = 8; j > 0; j--) {
  147. for (var i = 1; i < 9; i++) {
  148. (str = (jack.find(el => el.includes([i] + [j])))) ? str = str.replace(/[^a-zA-Z]+/g, ''): str = "";
  149. if (str == "") {
  150. count++;
  151. str = count.toString();
  152. if (!isNaN(str2.charAt(str2.length - 1))) str2 = str2.slice(0, -1);
  153. else {
  154. count = 1;
  155. str = count.toString()
  156. }
  157. }
  158. str2 += str;
  159. if (i == 8) {
  160. count = 0;
  161. str2 += "/";
  162. }
  163. }
  164. }
  165. str2 = str2.slice(0, -1);
  166. //str2=str2+" KQkq - 0"
  167. color = "";
  168. wk = wq = bk = bq = "0";
  169. const move = $('vertical-move-list')
  170. .children();
  171. if (move.length < 2) {
  172. stop_b = stop_w = s_br = s_br2 = s_wr = s_wr2 = 0;
  173. }
  174. if (stop_b != 1) {
  175. if (move.find(".black.node:contains('K')")
  176. .length) {
  177. bk = "";
  178. bq = "";
  179. stop_b = 1;
  180. console.log('debug secb');
  181. }
  182. } else {
  183. bq = "";
  184. bk = "";
  185. }
  186. if (stop_b != 1)(bk = (move.find(".black.node:contains('O-O'):not(:contains('O-O-O'))")
  187. .length) ? "" : "k") ? (bq = (move.find(".black.node:contains('O-O-O')")
  188. .length) ? bk = "" : "q") : bq = "";
  189. if (s_br != 1) {
  190. if (move.find(".black.node:contains('R')")
  191. .text()
  192. .match('[abcd]+')) {
  193. bq = "";
  194. s_br = 1
  195. }
  196. } else bq = "";
  197. if (s_br2 != 1) {
  198. if (move.find(".black.node:contains('R')")
  199. .text()
  200. .match('[hgf]+')) {
  201. bk = "";
  202. s_br2 = 1
  203. }
  204. } else bk = "";
  205. if (stop_b == 0) {
  206. if (s_br == 0)
  207. if (move.find(".white.node:contains('xa8')")
  208. .length > 0) {
  209. bq = "";
  210. s_br = 1;
  211. console.log('debug b castle_r');
  212. }
  213. if (s_br2 == 0)
  214. if (move.find(".white.node:contains('xh8')")
  215. .length > 0) {
  216. bk = "";
  217. s_br2 = 1;
  218. console.log('debug b castle_l');
  219. }
  220. }
  221. if (stop_w != 1) {
  222. if (move.find(".white.node:contains('K')")
  223. .length) {
  224. wk = "";
  225. wq = "";
  226. stop_w = 1;
  227. console.log('debug secw');
  228. }
  229. } else {
  230. wq = "";
  231. wk = "";
  232. }
  233. if (stop_w != 1)(wk = (move.find(".white.node:contains('O-O'):not(:contains('O-O-O'))")
  234. .length) ? "" : "K") ? (wq = (move.find(".white.node:contains('O-O-O')")
  235. .length) ? wk = "" : "Q") : wq = "";
  236. if (s_wr != 1) {
  237. if (move.find(".white.node:contains('R')")
  238. .text()
  239. .match('[abcd]+')) {
  240. wq = "";
  241. s_wr = 1
  242. }
  243. } else wq = "";
  244. if (s_wr2 != 1) {
  245. if (move.find(".white.node:contains('R')")
  246. .text()
  247. .match('[hgf]+')) {
  248. wk = "";
  249. s_wr2 = 1
  250. }
  251. } else wk = "";
  252. if (stop_w == 0) {
  253. if (s_wr == 0)
  254. if (move.find(".black.node:contains('xa1')")
  255. .length > 0) {
  256. wq = "";
  257. s_wr = 1;
  258. console.log('debug w castle_l');
  259. }
  260. if (s_wr2 == 0)
  261. if (move.find(".black.node:contains('xh1')")
  262. .length > 0) {
  263. wk = "";
  264. s_wr2 = 1;
  265. console.log('debug w castle_r');
  266. }
  267. }
  268. if ($('.coordinates')
  269. .children()
  270. .first()
  271. .text() == 1) {
  272. str2 = str2 + " b " + wk + wq + bk + bq;
  273. color = "white";
  274. } else {
  275. str2 = str2 + " w " + wk + wq + bk + bq;
  276. color = "black";
  277. }
  278. //console.log(str2);
  279. return str2;
  280. }
  281. myFunctions.color = function(dat){
  282. response = dat;
  283. var res1 = response.substring(0, 2);
  284. var res2 = response.substring(2, 4);
  285.  
  286. // Check if automove is enabled and make the move
  287. if(myVars.autoMove === true){
  288. console.log(`Auto move enabled, moving from ${res1} to ${res2}`);
  289. myFunctions.movePiece(res1, res2);
  290. } else {
  291. console.log(`Auto move disabled, highlighting ${res1} to ${res2}`);
  292. }
  293. isThinking = false;
  294.  
  295. res1 = res1.replace(/^a/, "1")
  296. .replace(/^b/, "2")
  297. .replace(/^c/, "3")
  298. .replace(/^d/, "4")
  299. .replace(/^e/, "5")
  300. .replace(/^f/, "6")
  301. .replace(/^g/, "7")
  302. .replace(/^h/, "8");
  303. res2 = res2.replace(/^a/, "1")
  304. .replace(/^b/, "2")
  305. .replace(/^c/, "3")
  306. .replace(/^d/, "4")
  307. .replace(/^e/, "5")
  308. .replace(/^f/, "6")
  309. .replace(/^g/, "7")
  310. .replace(/^h/, "8");
  311.  
  312. // Use custom highlight color if available
  313. const highlightColor = myVars.highlightColor || 'rgb(235, 97, 80)';
  314.  
  315. $(board.nodeName)
  316. .prepend(`<div class="highlight square-${res2} bro" style="background-color: ${highlightColor}; opacity: 0.71;" data-test-element="highlight"></div>`)
  317. .children(':first')
  318. .delay(1800)
  319. .queue(function() {
  320. $(this)
  321. .remove();
  322. });
  323. $(board.nodeName)
  324. .prepend(`<div class="highlight square-${res1} bro" style="background-color: ${highlightColor}; opacity: 0.71;" data-test-element="highlight"></div>`)
  325. .children(':first')
  326. .delay(1800)
  327. .queue(function() {
  328. $(this)
  329. .remove();
  330. });
  331. }
  332.  
  333. myFunctions.movePiece = function(from, to) {
  334. // Check if the move is legal before attempting to make it
  335. let isLegalMove = false;
  336. let moveObject = null;
  337. for (let each = 0; each < board.game.getLegalMoves().length; each++) {
  338. if (board.game.getLegalMoves()[each].from === from &&
  339. board.game.getLegalMoves()[each].to === to) {
  340. isLegalMove = true;
  341. moveObject = board.game.getLegalMoves()[each];
  342. break;
  343. }
  344. }
  345. if (!isLegalMove) {
  346. console.log(`Attempted illegal move: ${from} to ${to}`);
  347. return;
  348. }
  349. // Add a small delay before making the move to simulate human reaction time
  350. setTimeout(() => {
  351. try {
  352. // Make the actual move
  353. board.game.move({
  354. ...moveObject,
  355. promotion: moveObject.promotion || 'q', // Default to queen for simplicity
  356. animate: true,
  357. userGenerated: true
  358. });
  359. console.log(`Successfully moved from ${from} to ${to}`);
  360. } catch (error) {
  361. console.error("Error making move:", error);
  362. }
  363. }, 100 + Math.random() * 300); // Small random delay to appear more human-like
  364. }
  365.  
  366. // Replace simple movement simulation with this more advanced version
  367. function simulateNaturalMouseMovement(from, to, callback) {
  368. // Convert chess coordinates to screen positions
  369. const fromPos = getSquarePosition(from);
  370. const toPos = getSquarePosition(to);
  371.  
  372. // Create a bezier curve path with a slight variance
  373. const controlPoint1 = {
  374. x: fromPos.x + (toPos.x - fromPos.x) * 0.3 + (Math.random() * 40 - 20),
  375. y: fromPos.y + (toPos.y - fromPos.y) * 0.1 + (Math.random() * 40 - 20)
  376. };
  377.  
  378. const controlPoint2 = {
  379. x: fromPos.x + (toPos.x - fromPos.x) * 0.7 + (Math.random() * 40 - 20),
  380. y: fromPos.y + (toPos.y - fromPos.y) * 0.9 + (Math.random() * 40 - 20)
  381. };
  382.  
  383. // Calculate movement duration based on distance
  384. const distance = Math.sqrt(Math.pow(toPos.x - fromPos.x, 2) + Math.pow(toPos.y - fromPos.y, 2));
  385. const baseDuration = 300 + Math.random() * 400;
  386. const movementDuration = baseDuration + distance * (0.5 + Math.random() * 0.5);
  387.  
  388. // Create array of points along path
  389. const steps = 15 + Math.floor(distance / 30);
  390. const points = [];
  391.  
  392. for (let i = 0; i <= steps; i++) {
  393. const t = i / steps;
  394. points.push(getBezierPoint(t, fromPos, controlPoint1, controlPoint2, toPos));
  395. }
  396.  
  397. // Execute the movement with variable speed
  398. executeMouseMovement(points, 0, movementDuration / steps, callback);
  399. }
  400.  
  401. // Add these functions for more realistic timing
  402. function calculateMoveComplexity(from, to) {
  403. // Approximate complexity based on piece type, capture, check, etc.
  404. // Returns a value between 0 (simple) and 1 (complex)
  405. return Math.random() * 0.7 + 0.3; // Placeholder implementation
  406. }
  407.  
  408. function calculateHumanLikeDelay(complexity) {
  409. // More complex positions take longer to think about
  410. const baseDelay = 500; // Base delay in ms
  411. const complexityFactor = 2500; // Max additional delay for complex positions
  412. return baseDelay + (complexity * complexityFactor * Math.random());
  413. }
  414.  
  415. function getRandomThinkingDelay() {
  416. // Humans don't immediately start calculating
  417. return 300 + Math.random() * 700;
  418. }
  419.  
  420. function parser(e) {
  421. if(e.data.includes('bestmove')) {
  422. const bestMove = e.data.split(' ')[1];
  423. // Extract multiple moves from engine analysis if available
  424. let alternativeMoves = [bestMove];
  425. try {
  426. if (e.data.includes('pv')) {
  427. // Try to extract alternative moves from multiPV or previous info lines
  428. const lines = e.data.split('\n')
  429. .filter(line => line.includes(' pv '))
  430. .map(line => {
  431. const pvIndex = line.indexOf(' pv ');
  432. return line.substring(pvIndex + 4).split(' ')[0];
  433. });
  434. if (lines.length > 1) {
  435. alternativeMoves = lines;
  436. }
  437. }
  438. } catch (error) {
  439. console.log("Error extracting alternative moves", error);
  440. }
  441. // Decide whether to use best move or an alternative
  442. let moveToPlay = bestMove;
  443. const currentDepth = lastValue;
  444. // For higher depths, sometimes choose alternative moves
  445. if (currentDepth >= 15 && alternativeMoves.length > 1 && Math.random() < 0.35) {
  446. // Select a random move from top 5 (or fewer if not available)
  447. const maxIndex = Math.min(5, alternativeMoves.length);
  448. const randomIndex = Math.floor(Math.random() * (maxIndex - 1)) + 1; // Skip index 0 (best move)
  449. moveToPlay = alternativeMoves[randomIndex] || bestMove;
  450. console.log(`Using alternative move ${moveToPlay} instead of best move ${bestMove}`);
  451. } else if (Math.random() < getBlunderProbability()) {
  452. // Sometimes make a "human-like" suboptimal move
  453. moveToPlay = generateHumanLikeMove(bestMove, e.data);
  454. console.log(`Using human-like move ${moveToPlay} instead of best move ${bestMove}`);
  455. }
  456. myFunctions.color(moveToPlay);
  457. isThinking = false;
  458. }
  459. }
  460.  
  461. function getBlunderProbability() {
  462. // Use custom blunder rate from slider if available
  463. const userBlunderRate = myVars.blunderRate !== undefined ? myVars.blunderRate : 0.05;
  464.  
  465. // Make blunder probability vary based on multiple factors
  466. const gamePhase = estimateGamePhase();
  467. const timeRemaining = estimateTimeRemaining();
  468. const complexity = estimatePositionComplexity();
  469.  
  470. // Base probability comes from user settings
  471. let baseProb = userBlunderRate;
  472.  
  473. // More likely to blunder in time pressure
  474. if (timeRemaining < 30) {
  475. baseProb += 0.1 * (1 - (timeRemaining / 30));
  476. }
  477.  
  478. // More likely to blunder in complex positions
  479. if (complexity > 0.6) {
  480. baseProb += 0.05 * (complexity - 0.6) * 2;
  481. }
  482.  
  483. // More likely to blunder in the endgame when tired
  484. if (gamePhase > 30) {
  485. baseProb += 0.03 * ((gamePhase - 30) / 10);
  486. }
  487.  
  488. // Add randomness to make it unpredictable
  489. return Math.min(0.4, baseProb * (0.7 + Math.random() * 0.6));
  490. }
  491.  
  492. function estimateGamePhase() {
  493. // Estimate how far the game has progressed (0-40 approx)
  494. try {
  495. const moveList = $('vertical-move-list').children().length;
  496. return moveList / 2; // Rough estimate of move number
  497. } catch (e) {
  498. return 15; // Default to middle game
  499. }
  500. }
  501.  
  502. function estimateTimeRemaining() {
  503. // Try to get the clock time if available
  504. try {
  505. const clockEl = document.querySelector('.clock-component');
  506. if (clockEl) {
  507. const timeText = clockEl.textContent;
  508. if (timeText.includes(':')) {
  509. const parts = timeText.split(':');
  510. if (parts.length === 2) {
  511. const minutes = parseInt(parts[0]);
  512. const seconds = parseInt(parts[1]);
  513. return minutes * 60 + seconds;
  514. }
  515. } else {
  516. // Handle single number format (e.g., just seconds)
  517. return parseInt(timeText);
  518. }
  519. }
  520. // Try alternative clock selectors
  521. const altClockEl = document.querySelector('.clock-time-monospace') ||
  522. document.querySelector('.clock-time') ||
  523. document.querySelector('[data-cy="clock-time"]');
  524. if (altClockEl) {
  525. const timeText = altClockEl.textContent;
  526. if (timeText.includes(':')) {
  527. const parts = timeText.split(':');
  528. if (parts.length === 2) {
  529. const minutes = parseInt(parts[0]);
  530. const seconds = parseInt(parts[1]);
  531. return minutes * 60 + seconds;
  532. }
  533. } else {
  534. return parseInt(timeText);
  535. }
  536. }
  537. } catch (e) {
  538. console.log("Error getting time remaining:", e);
  539. }
  540.  
  541. // Default value if clock can't be read
  542. return 180; // 3 minutes as default
  543. }
  544.  
  545. function estimatePositionComplexity() {
  546. // Calculate a complexity score between 0-1
  547. // This would ideally analyze the position for tactical elements
  548. return Math.random() * 0.8 + 0.2; // Placeholder
  549. }
  550.  
  551. function generateHumanLikeMove(bestMove, engineData) {
  552. // Significantly enhance the human-like behavior
  553. // Sometimes choose 2nd, 3rd, or even 4th best moves
  554. if (engineData.includes('pv') && Math.random() < 0.4) {
  555. try {
  556. // Extract multiple lines from engine analysis
  557. const lines = engineData.split('\n')
  558. .filter(line => line.includes(' pv '))
  559. .map(line => {
  560. const pvIndex = line.indexOf(' pv ');
  561. return line.substring(pvIndex + 4).split(' ')[0];
  562. });
  563. if (lines.length > 1) {
  564. // Weight moves by their quality (prefer better moves, but sometimes choose worse ones)
  565. const moveIndex = Math.floor(Math.pow(Math.random(), 2.5) * Math.min(lines.length, 4));
  566. return lines[moveIndex] || bestMove;
  567. }
  568. } catch (e) {
  569. console.log("Error extracting alternative moves", e);
  570. }
  571. }
  572.  
  573. // Occasionally make a typical human error based on common patterns
  574. if (Math.random() < 0.15) {
  575. // Approximate a plausible human move (e.g., moving to adjacent square)
  576. const fromSquare = bestMove.substring(0, 2);
  577. const toSquare = bestMove.substring(2, 4);
  578.  
  579. // Simple adjustment - occasionally play a shorter move (undershoot)
  580. if (Math.random() < 0.7) {
  581. const files = "abcdefgh";
  582. const ranks = "12345678";
  583. const fromFile = fromSquare.charAt(0);
  584. const fromRank = fromSquare.charAt(1);
  585. const toFile = toSquare.charAt(0);
  586. const toRank = toSquare.charAt(1);
  587.  
  588. // Calculate direction
  589. const fileDiff = files.indexOf(toFile) - files.indexOf(fromFile);
  590. const rankDiff = ranks.indexOf(toRank) - ranks.indexOf(fromRank);
  591.  
  592. // Sometimes undershoot by one square
  593. if (Math.abs(fileDiff) > 1 || Math.abs(rankDiff) > 1) {
  594. const newToFile = files[files.indexOf(fromFile) + (fileDiff > 0 ? Math.max(1, fileDiff-1) : Math.min(-1, fileDiff+1))];
  595. const newToRank = ranks[ranks.indexOf(fromRank) + (rankDiff > 0 ? Math.max(1, rankDiff-1) : Math.min(-1, rankDiff+1))];
  596.  
  597. // Check if the new square is valid
  598. if (newToFile && newToRank) {
  599. const alternativeMove = fromSquare + newToFile + newToRank;
  600. // Verify this is a legal move before returning
  601. for (let each=0; each<board.game.getLegalMoves().length; each++) {
  602. if (board.game.getLegalMoves()[each].from === fromSquare &&
  603. board.game.getLegalMoves()[each].to === newToFile + newToRank) {
  604. return alternativeMove;
  605. }
  606. }
  607. }
  608. }
  609. }
  610. }
  611.  
  612. return bestMove;
  613. }
  614.  
  615. myFunctions.reloadChessEngine = function() {
  616. console.log(`Reloading the chess engine!`);
  617.  
  618. engine.engine.terminate();
  619. isThinking = false;
  620. myFunctions.loadChessEngine();
  621. }
  622.  
  623. myFunctions.loadChessEngine = function() {
  624. if(!stockfishObjectURL) {
  625. stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText('stockfish.js')], {type: 'application/javascript'}));
  626. }
  627. console.log(stockfishObjectURL);
  628. if(stockfishObjectURL) {
  629. engine.engine = new Worker(stockfishObjectURL);
  630.  
  631. engine.engine.onmessage = e => {
  632. parser(e);
  633. };
  634. engine.engine.onerror = e => {
  635. console.log("Worker Error: "+e);
  636. };
  637.  
  638. engine.engine.postMessage('ucinewgame');
  639. }
  640. console.log('loaded chess engine');
  641. }
  642.  
  643. var lastValue = 11;
  644.  
  645.  
  646. myFunctions.runChessEngine = function(depth) {
  647. // Get time-adjusted depth
  648. var adjustedDepth = getAdjustedDepth();
  649. // Get position type
  650. var fen = board.game.getFEN();
  651. var positionType = analyzePositionType(fen);
  652. // Log the depth adjustment
  653. console.log(`Original depth: ${depth}, Adjusted for time/position: ${adjustedDepth}`);
  654. engine.engine.postMessage(`position fen ${fen}`);
  655. console.log('updated: ' + `position fen ${fen}`);
  656. isThinking = true;
  657. // Use multipv for alternative moves when depth is high
  658. if (depth >= 15) {
  659. engine.engine.postMessage(`setoption name MultiPV value 5`);
  660. } else {
  661. engine.engine.postMessage(`setoption name MultiPV value 1`);
  662. }
  663. engine.engine.postMessage(`go depth ${adjustedDepth}`);
  664. lastValue = depth; // Keep original depth for UI display
  665. }
  666.  
  667. function analyzePositionType(fen) {
  668. // Determine position type: opening, middlegame, endgame, tactical
  669. const piecesCount = fen.split(' ')[0].match(/[pnbrqkPNBRQK]/g).length;
  670.  
  671. if (piecesCount > 25) return 'opening';
  672. if (piecesCount < 12) return 'endgame';
  673. return 'middlegame';
  674. }
  675.  
  676. function adjustDepthByPosition(requestedDepth, positionType) {
  677. // Humans play more accurately in different phases
  678. if (positionType === 'opening' && Math.random() < 0.7) {
  679. // In openings, humans often play memorized moves
  680. return requestedDepth + Math.floor(Math.random() * 3);
  681. } else if (positionType === 'endgame' && Math.random() < 0.5) {
  682. // In endgames, calculation may be more/less precise
  683. return requestedDepth + (Math.random() < 0.5 ? -1 : 1);
  684. }
  685.  
  686. // Occasionally randomize depth slightly
  687. return Math.max(1, requestedDepth + (Math.random() < 0.3 ? Math.floor(Math.random() * 3) - 1 : 0));
  688. }
  689.  
  690. myFunctions.autoRun = function(lstValue){
  691. if(board.game.getTurn() == board.game.getPlayingAs()){
  692. myFunctions.runChessEngine(lstValue);
  693. }
  694. }
  695.  
  696. document.onkeydown = function(e) {
  697. switch (e.keyCode) {
  698. case 81:
  699. myFunctions.runChessEngine(1);
  700. break;
  701. case 87:
  702. myFunctions.runChessEngine(2);
  703. break;
  704. case 69:
  705. myFunctions.runChessEngine(3);
  706. break;
  707. case 82:
  708. myFunctions.runChessEngine(4);
  709. break;
  710. case 84:
  711. myFunctions.runChessEngine(5);
  712. break;
  713. case 89:
  714. myFunctions.runChessEngine(6);
  715. break;
  716. case 85:
  717. myFunctions.runChessEngine(7);
  718. break;
  719. case 73:
  720. myFunctions.runChessEngine(8);
  721. break;
  722. case 79:
  723. myFunctions.runChessEngine(9);
  724. break;
  725. case 80:
  726. myFunctions.runChessEngine(10);
  727. break;
  728. case 65:
  729. myFunctions.runChessEngine(11);
  730. break;
  731. case 83:
  732. myFunctions.runChessEngine(12);
  733. break;
  734. case 68:
  735. myFunctions.runChessEngine(13);
  736. break;
  737. case 70:
  738. myFunctions.runChessEngine(14);
  739. break;
  740. case 71:
  741. myFunctions.runChessEngine(15);
  742. break;
  743. case 72:
  744. myFunctions.runChessEngine(16);
  745. break;
  746. case 74:
  747. myFunctions.runChessEngine(17);
  748. break;
  749. case 75:
  750. myFunctions.runChessEngine(18);
  751. break;
  752. case 76:
  753. myFunctions.runChessEngine(19);
  754. break;
  755. case 90:
  756. myFunctions.runChessEngine(20);
  757. break;
  758. case 88:
  759. myFunctions.runChessEngine(21);
  760. break;
  761. case 67:
  762. myFunctions.runChessEngine(22);
  763. break;
  764. case 86:
  765. myFunctions.runChessEngine(23);
  766. break;
  767. case 66:
  768. myFunctions.runChessEngine(24);
  769. break;
  770. case 78:
  771. myFunctions.runChessEngine(25);
  772. break;
  773. case 77:
  774. myFunctions.runChessEngine(26);
  775. break;
  776. case 187:
  777. myFunctions.runChessEngine(100);
  778. break;
  779. }
  780. };
  781.  
  782. myFunctions.spinner = function() {
  783. if(isThinking == true){
  784. $('#thinking-indicator').addClass('active');
  785. }
  786. if(isThinking == false) {
  787. $('#thinking-indicator').removeClass('active');
  788. }
  789. }
  790.  
  791. let dynamicStyles = null;
  792.  
  793. function addAnimation(body) {
  794. if (!dynamicStyles) {
  795. dynamicStyles = document.createElement('style');
  796. dynamicStyles.type = 'text/css';
  797. document.head.appendChild(dynamicStyles);
  798. }
  799.  
  800. dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
  801. }
  802.  
  803. var loaded = false;
  804. myFunctions.loadEx = function(){
  805. try{
  806. var tmpStyle;
  807. var tmpDiv;
  808. board = $('chess-board')[0] || $('wc-chess-board')[0];
  809. myVars.board = board;
  810.  
  811. var div = document.createElement('div')
  812. var content = `
  813. <div class="chess-bot-container">
  814. <div class="bot-header">
  815. <div class="bot-logo">
  816. <svg viewBox="0 0 24 24" width="24" height="24">
  817. <path fill="currentColor" d="M19,22H5V20H19V22M17,10C15.58,10 14.26,10.77 13.55,12H13V7H16V5H13V2H11V5H8V7H11V12H10.45C9.74,10.77 8.42,10 7,10A5,5 0 0,0 2,15A5,5 0 0,0 7,20H17A5,5 0 0,0 22,15A5,5 0 0,0 17,10M7,18A3,3 0 0,1 4,15A3,3 0 0,1 7,12A3,3 0 0,1 10,15A3,3 0 0,1 7,18M17,18A3,3 0 0,1 14,15A3,3 0 0,1 17,12A3,3 0 0,1 20,15A3,3 0 0,1 17,18Z" />
  818. </svg>
  819. </div>
  820. <h3 class="bot-title">Panel Pro By @akashdeep</h3>
  821. <div id="thinking-indicator" class="thinking-indicator">
  822. <span class="dot dot1"></span>
  823. <span class="dot dot2"></span>
  824. <span class="dot dot3"></span>
  825. </div>
  826. </div>
  827.  
  828. <div class="bot-tabs">
  829. <button class="tab-button active" data-tab="main-settings">Main</button>
  830. <button class="tab-button" data-tab="style-settings">Play Style</button>
  831. <button class="tab-button" data-tab="advanced-settings">Advanced</button>
  832. </div>
  833.  
  834. <div class="bot-tabs-content">
  835. <div class="tab-content active" id="main-settings">
  836. <div class="bot-info">
  837. <div class="depth-card">
  838. <p id="depthText" class="depth-display">Current Depth: <strong>11</strong></p>
  839. <p class="key-hint">Press a key (Q-Z) to change depth</p>
  840.  
  841. <div class="depth-control">
  842. <label for="depthSlider">Depth/ELO:</label>
  843. <div class="slider-controls">
  844. <button class="depth-button" id="decreaseDepth">-</button>
  845. <input type="range" id="depthSlider" min="1" max="21" value="11" class="depth-slider">
  846. <button class="depth-button" id="increaseDepth">+</button>
  847. </div>
  848. <span id="depthValue">11</span>
  849. </div>
  850. </div>
  851. </div>
  852.  
  853. <div class="bot-controls">
  854. <div class="control-group">
  855. <div class="control-item toggle-container">
  856. <input type="checkbox" id="autoRun" name="autoRun" class="toggle-input" value="false">
  857. <label for="autoRun" class="toggle-label">
  858. <span class="toggle-button"></span>
  859. <span class="toggle-text">Auto Run</span>
  860. </label>
  861. </div>
  862.  
  863. <div class="control-item toggle-container">
  864. <input type="checkbox" id="autoMove" name="autoMove" class="toggle-input" value="false">
  865. <label for="autoMove" class="toggle-label">
  866. <span class="toggle-button"></span>
  867. <span class="toggle-text">Auto Move</span>
  868. </label>
  869. </div>
  870. </div>
  871.  
  872. <div class="control-group">
  873. <div class="control-item slider-container">
  874. <label for="timeDelayMin">Min Delay (sec)</label>
  875. <input type="number" id="timeDelayMin" name="timeDelayMin" min="0.1" value="0.1" step="0.1" class="number-input">
  876. </div>
  877.  
  878. <div class="control-item slider-container">
  879. <label for="timeDelayMax">Max Delay (sec)</label>
  880. <input type="number" id="timeDelayMax" name="timeDelayMax" min="0.1" value="1" step="0.1" class="number-input">
  881. </div>
  882. </div>
  883. </div>
  884. </div>
  885.  
  886. <div class="tab-content" id="style-settings">
  887. <div class="playStyle-controls">
  888. <h4 class="settings-section-title">Playing Style Settings</h4>
  889.  
  890. <div class="style-slider-container">
  891. <label for="aggressiveSlider">Aggressive Play:</label>
  892. <input type="range" id="aggressiveSlider" min="1" max="10" value="5" class="style-slider">
  893. <span id="aggressiveValue">5</span>
  894. </div>
  895.  
  896. <div class="style-slider-container">
  897. <label for="defensiveSlider">Defensive Play:</label>
  898. <input type="range" id="defensiveSlider" min="1" max="10" value="5" class="style-slider">
  899. <span id="defensiveValue">5</span>
  900. </div>
  901.  
  902. <div class="style-slider-container">
  903. <label for="tacticalSlider">Tactical Play:</label>
  904. <input type="range" id="tacticalSlider" min="1" max="10" value="5" class="style-slider">
  905. <span id="tacticalValue">5</span>
  906. </div>
  907.  
  908. <div class="style-slider-container">
  909. <label for="positionalSlider">Positional Play:</label>
  910. <input type="range" id="positionalSlider" min="1" max="10" value="5" class="style-slider">
  911. <span id="positionalValue">5</span>
  912. </div>
  913.  
  914. <div class="style-slider-container">
  915. <label for="blunderRateSlider">Blunder Rate:</label>
  916. <input type="range" id="blunderRateSlider" min="0" max="10" value="2" class="style-slider">
  917. <span id="blunderRateValue">2</span>
  918. </div>
  919. </div>
  920. </div>
  921.  
  922. <div class="tab-content" id="advanced-settings">
  923. <div class="advanced-controls">
  924. <h4 class="settings-section-title">Advanced Settings</h4>
  925.  
  926. <div class="control-item toggle-container">
  927. <input type="checkbox" id="adaptToRating" name="adaptToRating" class="toggle-input" value="true" checked>
  928. <label for="adaptToRating" class="toggle-label">
  929. <span class="toggle-button"></span>
  930. <span class="toggle-text">Adapt to opponent rating</span>
  931. </label>
  932. </div>
  933.  
  934. <div class="control-item toggle-container">
  935. <input type="checkbox" id="useOpeningBook" name="useOpeningBook" class="toggle-input" value="true" checked>
  936. <label for="useOpeningBook" class="toggle-label">
  937. <span class="toggle-button"></span>
  938. <span class="toggle-text">Use personalized openings</span>
  939. </label>
  940. </div>
  941.  
  942. <div class="highlight-color-picker">
  943. <label for="highlightColor">Move highlight color:</label>
  944. <input type="color" id="highlightColor" value="#eb6150" class="color-input">
  945. </div>
  946.  
  947. <div class="opening-selection">
  948. <label for="preferredOpeningSelect">Preferred Opening:</label>
  949. <select id="preferredOpeningSelect" class="select-input">
  950. <option value="random">Random</option>
  951. <option value="e4">e4 (King's Pawn)</option>
  952. <option value="d4">d4 (Queen's Pawn)</option>
  953. <option value="c4">c4 (English)</option>
  954. <option value="Nf3">Nf3 (Réti)</option>
  955. </select>
  956. </div>
  957. </div>
  958. </div>
  959. </div>
  960.  
  961. <div class="bot-actions">
  962. <button type="button" id="relEngBut" class="action-button primary-button" onclick="document.myFunctions.reloadChessEngine()">
  963. <svg viewBox="0 0 24 24" width="16" height="16">
  964. <path fill="currentColor" d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z" />
  965. </svg>
  966. Reload Engine
  967. </button>
  968.  
  969. <button type="button" id="isBut" class="action-button secondary-button" onclick="window.confirm('Can I take you to the issues page?') ? document.location = 'https://github.com/Auzgame/userscripts/issues' : console.log('canceled')">
  970. <svg viewBox="0 0 24 24" width="16" height="16">
  971. <path fill="currentColor" d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
  972. </svg>
  973. Report Issue
  974. </button>
  975. </div>
  976. </div>`;
  977. div.innerHTML = content;
  978. div.setAttribute('id','settingsContainer');
  979.  
  980. board.parentElement.parentElement.appendChild(div);
  981.  
  982. //Add CSS styles
  983. var botStyles = document.createElement('style');
  984. botStyles.innerHTML = `
  985. @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
  986.  
  987. #settingsContainer {
  988. background-color: #1e1e2e;
  989. color: #cdd6f4;
  990. border-radius: 12px;
  991. padding: 20px;
  992. margin-top: 15px;
  993. box-shadow: 0 8px 24px rgba(0,0,0,0.3);
  994. font-family: 'Roboto', sans-serif;
  995. max-width: 400px;
  996. margin-left: auto;
  997. margin-right: auto;
  998. border: 1px solid #313244;
  999. }
  1000.  
  1001. .chess-bot-container {
  1002. display: flex;
  1003. flex-direction: column;
  1004. gap: 16px;
  1005. }
  1006.  
  1007. .bot-header {
  1008. display: flex;
  1009. align-items: center;
  1010. justify-content: center;
  1011. gap: 10px;
  1012. margin-bottom: 5px;
  1013. position: relative;
  1014. }
  1015.  
  1016. .bot-logo {
  1017. display: flex;
  1018. align-items: center;
  1019. justify-content: center;
  1020. color: #89b4fa;
  1021. }
  1022.  
  1023. .bot-title {
  1024. margin: 0;
  1025. color: #89b4fa;
  1026. font-size: 20px;
  1027. font-weight: 500;
  1028. letter-spacing: 0.5px;
  1029. }
  1030.  
  1031. .thinking-indicator {
  1032. position: absolute;
  1033. right: 0;
  1034. display: none;
  1035. align-items: center;
  1036. }
  1037.  
  1038. .thinking-indicator.active {
  1039. display: flex;
  1040. }
  1041.  
  1042. .dot {
  1043. width: 8px;
  1044. height: 8px;
  1045. margin: 0 2px;
  1046. background-color: #89b4fa;
  1047. border-radius: 50%;
  1048. opacity: 0.6;
  1049. }
  1050.  
  1051. .dot1 {
  1052. animation: pulse 1.5s infinite;
  1053. }
  1054.  
  1055. .dot2 {
  1056. animation: pulse 1.5s infinite 0.3s;
  1057. }
  1058.  
  1059. .dot3 {
  1060. animation: pulse 1.5s infinite 0.6s;
  1061. }
  1062.  
  1063. @keyframes pulse {
  1064. 0%, 100% {
  1065. transform: scale(1);
  1066. opacity: 0.6;
  1067. }
  1068. 50% {
  1069. transform: scale(1.3);
  1070. opacity: 1;
  1071. }
  1072. }
  1073.  
  1074. .bot-tabs {
  1075. display: flex;
  1076. gap: 2px;
  1077. margin-bottom: -15px;
  1078. }
  1079.  
  1080. .tab-button {
  1081. background-color: #313244;
  1082. color: #a6adc8;
  1083. border: none;
  1084. border-radius: 8px 8px 0 0;
  1085. padding: 8px 16px;
  1086. cursor: pointer;
  1087. font-size: 14px;
  1088. font-weight: 500;
  1089. transition: all 0.2s;
  1090. flex: 1;
  1091. text-align: center;
  1092. }
  1093.  
  1094. .tab-button:hover {
  1095. background-color: #45475a;
  1096. color: #cdd6f4;
  1097. }
  1098.  
  1099. .tab-button.active {
  1100. background-color: #45475a;
  1101. color: #cdd6f4;
  1102. }
  1103.  
  1104. .bot-tabs-content {
  1105. background-color: #45475a;
  1106. border-radius: 0 8px 8px 8px;
  1107. padding: 16px;
  1108. }
  1109.  
  1110. .tab-content {
  1111. display: none;
  1112. }
  1113.  
  1114. .tab-content.active {
  1115. display: block;
  1116. }
  1117.  
  1118. .settings-section-title {
  1119. margin-top: 0;
  1120. margin-bottom: 12px;
  1121. color: #89b4fa;
  1122. font-size: 16px;
  1123. font-weight: 500;
  1124. text-align: center;
  1125. }
  1126.  
  1127. .bot-info {
  1128. display: flex;
  1129. justify-content: center;
  1130. margin-bottom: 5px;
  1131. }
  1132.  
  1133. .depth-card {
  1134. background-color: #313244;
  1135. border-radius: 8px;
  1136. padding: 12px 16px;
  1137. text-align: center;
  1138. width: 100%;
  1139. border: 1px solid #45475a;
  1140. }
  1141.  
  1142. .depth-display {
  1143. font-size: 16px;
  1144. margin: 0 0 5px 0;
  1145. font-weight: 400;
  1146. }
  1147.  
  1148. .depth-display strong {
  1149. color: #89b4fa;
  1150. font-weight: 600;
  1151. }
  1152.  
  1153. .key-hint {
  1154. font-size: 12px;
  1155. color: #a6adc8;
  1156. margin: 0;
  1157. font-weight: 300;
  1158. }
  1159.  
  1160. .bot-controls {
  1161. display: flex;
  1162. flex-direction: column;
  1163. gap: 16px;
  1164. }
  1165.  
  1166. .control-group {
  1167. display: grid;
  1168. grid-template-columns: 1fr 1fr;
  1169. gap: 12px;
  1170. }
  1171.  
  1172. .control-item {
  1173. display: flex;
  1174. flex-direction: column;
  1175. gap: 6px;
  1176. }
  1177.  
  1178. .toggle-container {
  1179. position: relative;
  1180. }
  1181.  
  1182. .toggle-input {
  1183. opacity: 0;
  1184. width: 0;
  1185. height: 0;
  1186. position: absolute;
  1187. }
  1188.  
  1189. .toggle-label {
  1190. display: flex;
  1191. align-items: center;
  1192. gap: 10px;
  1193. cursor: pointer;
  1194. }
  1195.  
  1196. .toggle-button {
  1197. position: relative;
  1198. display: inline-block;
  1199. width: 40px;
  1200. height: 20px;
  1201. background-color: #45475a;
  1202. border-radius: 20px;
  1203. transition: all 0.3s;
  1204. }
  1205.  
  1206. .toggle-button:before {
  1207. content: '';
  1208. position: absolute;
  1209. width: 16px;
  1210. height: 16px;
  1211. border-radius: 50%;
  1212. background-color: #cdd6f4;
  1213. top: 2px;
  1214. left: 2px;
  1215. transition: all 0.3s;
  1216. }
  1217.  
  1218. .toggle-input:checked + .toggle-label .toggle-button {
  1219. background-color: #89b4fa;
  1220. }
  1221.  
  1222. .toggle-input:checked + .toggle-label .toggle-button:before {
  1223. transform: translateX(20px);
  1224. }
  1225.  
  1226. .toggle-text {
  1227. font-size: 14px;
  1228. }
  1229.  
  1230. .slider-container {
  1231. display: flex;
  1232. flex-direction: column;
  1233. gap: 6px;
  1234. }
  1235.  
  1236. .slider-container label {
  1237. font-size: 13px;
  1238. color: #a6adc8;
  1239. }
  1240.  
  1241. .number-input {
  1242. width: 100%;
  1243. background: #313244;
  1244. border: 1px solid #45475a;
  1245. border-radius: 6px;
  1246. color: #cdd6f4;
  1247. padding: 8px 10px;
  1248. font-size: 14px;
  1249. transition: border-color 0.3s;
  1250. }
  1251.  
  1252. .number-input:focus {
  1253. outline: none;
  1254. border-color: #89b4fa;
  1255. }
  1256.  
  1257. .bot-actions {
  1258. display: grid;
  1259. grid-template-columns: 1fr 1fr;
  1260. gap: 12px;
  1261. margin-top: 5px;
  1262. }
  1263.  
  1264. .action-button {
  1265. display: flex;
  1266. align-items: center;
  1267. justify-content: center;
  1268. gap: 8px;
  1269. border: none;
  1270. border-radius: 8px;
  1271. padding: 10px 16px;
  1272. font-size: 14px;
  1273. font-weight: 500;
  1274. cursor: pointer;
  1275. transition: all 0.2s;
  1276. }
  1277.  
  1278. .primary-button {
  1279. background-color: #89b4fa;
  1280. color: #1e1e2e;
  1281. }
  1282.  
  1283. .primary-button:hover {
  1284. background-color: #b4befe;
  1285. transform: translateY(-2px);
  1286. box-shadow: 0 4px 8px rgba(137, 180, 250, 0.3);
  1287. }
  1288.  
  1289. .secondary-button {
  1290. background-color: #45475a;
  1291. color: #cdd6f4;
  1292. }
  1293.  
  1294. .secondary-button:hover {
  1295. background-color: #585b70;
  1296. transform: translateY(-2px);
  1297. box-shadow: 0 4px 8px rgba(69, 71, 90, 0.3);
  1298. }
  1299.  
  1300. .action-button:active {
  1301. transform: translateY(0);
  1302. }
  1303.  
  1304. .depth-control {
  1305. margin-top: 12px;
  1306. display: flex;
  1307. flex-direction: column;
  1308. gap: 8px;
  1309. }
  1310.  
  1311. .depth-control label {
  1312. font-size: 13px;
  1313. color: #a6adc8;
  1314. }
  1315.  
  1316. .slider-controls {
  1317. display: flex;
  1318. align-items: center;
  1319. gap: 8px;
  1320. }
  1321.  
  1322. .depth-slider {
  1323. flex: 1;
  1324. height: 6px;
  1325. -webkit-appearance: none;
  1326. appearance: none;
  1327. background: #45475a;
  1328. border-radius: 3px;
  1329. outline: none;
  1330. }
  1331.  
  1332. .depth-slider::-webkit-slider-thumb {
  1333. -webkit-appearance: none;
  1334. appearance: none;
  1335. width: 16px;
  1336. height: 16px;
  1337. border-radius: 50%;
  1338. background: #89b4fa;
  1339. cursor: pointer;
  1340. }
  1341.  
  1342. .depth-slider::-moz-range-thumb {
  1343. width: 16px;
  1344. height: 16px;
  1345. border-radius: 50%;
  1346. background: #89b4fa;
  1347. cursor: pointer;
  1348. }
  1349.  
  1350. .depth-button {
  1351. width: 24px;
  1352. height: 24px;
  1353. border-radius: 50%;
  1354. background: #45475a;
  1355. color: #cdd6f4;
  1356. border: none;
  1357. display: flex;
  1358. align-items: center;
  1359. justify-content: center;
  1360. cursor: pointer;
  1361. font-size: 16px;
  1362. font-weight: bold;
  1363. transition: background-color 0.2s;
  1364. }
  1365.  
  1366. .depth-button:hover {
  1367. background: #585b70;
  1368. }
  1369.  
  1370. #depthValue {
  1371. font-size: 14px;
  1372. font-weight: 500;
  1373. color: #89b4fa;
  1374. text-align: center;
  1375. }
  1376. `;
  1377. document.head.appendChild(botStyles);
  1378.  
  1379. //spinnerContainer
  1380. var spinCont = document.createElement('div');
  1381. spinCont.setAttribute('style','display:none;');
  1382. spinCont.setAttribute('id','overlay');
  1383. div.prepend(spinCont);
  1384.  
  1385. //spinner
  1386. var spinr = document.createElement('div')
  1387. spinr.setAttribute('style',`
  1388. margin: 0 auto;
  1389. height: 40px;
  1390. width: 40px;
  1391. animation: rotate 0.8s infinite linear;
  1392. border: 4px solid #89b4fa;
  1393. border-right-color: transparent;
  1394. border-radius: 50%;
  1395. box-shadow: 0 0 10px rgba(137, 180, 250, 0.4);
  1396. `);
  1397. spinCont.appendChild(spinr);
  1398. addAnimation(`@keyframes rotate {
  1399. 0% {
  1400. transform: rotate(0deg);
  1401. }
  1402. 100% {
  1403. transform: rotate(360deg);
  1404. }
  1405. }`);
  1406. $('#depthSlider').on('input', function() {
  1407. const depth = parseInt($(this).val());
  1408. $('#depthValue').text(depth);
  1409. lastValue = depth;
  1410. $('#depthText')[0].innerHTML = "Current Depth: <strong>" + depth + "</strong>";
  1411. });
  1412.  
  1413. $('#decreaseDepth').on('click', function() {
  1414. const currentDepth = parseInt($('#depthSlider').val());
  1415. if (currentDepth > 1) {
  1416. const newDepth = currentDepth - 1;
  1417. $('#depthSlider').val(newDepth).trigger('input');
  1418. }
  1419. });
  1420.  
  1421. $('#increaseDepth').on('click', function() {
  1422. const currentDepth = parseInt($('#depthSlider').val());
  1423. if (currentDepth < 26) {
  1424. const newDepth = currentDepth + 1;
  1425. $('#depthSlider').val(newDepth).trigger('input');
  1426. }
  1427. });
  1428.  
  1429. // Fix tab switching and initialize all controls
  1430. $(document).on('click', '.tab-button', function() {
  1431. $('.tab-button').removeClass('active');
  1432. $(this).addClass('active');
  1433.  
  1434. const tabId = $(this).data('tab');
  1435. $('.tab-content').removeClass('active');
  1436. $(`#${tabId}`).addClass('active');
  1437. });
  1438.  
  1439. // Initialize play style sliders with values from myVars
  1440. if (myVars.playStyle) {
  1441. $('#aggressiveSlider').val(Math.round(((myVars.playStyle.aggressive - 0.3) / 0.5) * 10));
  1442. $('#aggressiveValue').text($('#aggressiveSlider').val());
  1443.  
  1444. $('#defensiveSlider').val(Math.round(((myVars.playStyle.defensive - 0.3) / 0.5) * 10));
  1445. $('#defensiveValue').text($('#defensiveSlider').val());
  1446.  
  1447. $('#tacticalSlider').val(Math.round(((myVars.playStyle.tactical - 0.2) / 0.6) * 10));
  1448. $('#tacticalValue').text($('#tacticalSlider').val());
  1449.  
  1450. $('#positionalSlider').val(Math.round(((myVars.playStyle.positional - 0.2) / 0.6) * 10));
  1451. $('#positionalValue').text($('#positionalSlider').val());
  1452. }
  1453.  
  1454. // Set the blunder rate slider
  1455. const blunderRate = myVars.blunderRate !== undefined ? Math.round(myVars.blunderRate * 10) : 2;
  1456. $('#blunderRateSlider').val(blunderRate);
  1457. $('#blunderRateValue').text(blunderRate);
  1458.  
  1459. // Setup the style sliders
  1460. $('.style-slider').on('input', function() {
  1461. const value = $(this).val();
  1462. $(`#${this.id}Value`).text(value);
  1463.  
  1464. // Update the myVars.playStyle object
  1465. const styleType = this.id.replace('Slider', '');
  1466. if (styleType === 'blunderRate') {
  1467. myVars.blunderRate = parseFloat(value) / 10;
  1468. } else if (myVars.playStyle && styleType in myVars.playStyle) {
  1469. if (styleType === 'aggressive' || styleType === 'defensive') {
  1470. myVars.playStyle[styleType] = 0.3 + (parseFloat(value) / 10) * 0.5;
  1471. } else {
  1472. myVars.playStyle[styleType] = 0.2 + (parseFloat(value) / 10) * 0.6;
  1473. }
  1474. }
  1475. });
  1476.  
  1477. // Initialize advanced settings
  1478. if (myVars.adaptToRating !== undefined) {
  1479. $('#adaptToRating').prop('checked', myVars.adaptToRating);
  1480. }
  1481.  
  1482. if (myVars.useOpeningBook !== undefined) {
  1483. $('#useOpeningBook').prop('checked', myVars.useOpeningBook);
  1484. }
  1485.  
  1486. if (myVars.highlightColor) {
  1487. $('#highlightColor').val(myVars.highlightColor);
  1488. }
  1489.  
  1490. // Set up preferred opening selection
  1491. if (myVars.preferredOpenings && myVars.preferredOpenings.length === 1) {
  1492. $('#preferredOpeningSelect').val(myVars.preferredOpenings[0]);
  1493. } else {
  1494. $('#preferredOpeningSelect').val('random');
  1495. }
  1496.  
  1497. // Set up advanced settings event handlers
  1498. $('#adaptToRating').on('change', function() {
  1499. myVars.adaptToRating = $(this).prop('checked');
  1500. });
  1501.  
  1502. $('#useOpeningBook').on('change', function() {
  1503. myVars.useOpeningBook = $(this).prop('checked');
  1504. });
  1505.  
  1506. $('#highlightColor').on('input', function() {
  1507. myVars.highlightColor = $(this).val();
  1508. });
  1509.  
  1510. $('#preferredOpeningSelect').on('change', function() {
  1511. const selectedOpening = $(this).val();
  1512. if (selectedOpening === 'random') {
  1513. myVars.preferredOpenings = ["e4", "d4", "c4", "Nf3"].sort(() => Math.random() - 0.5);
  1514. } else {
  1515. myVars.preferredOpenings = [selectedOpening];
  1516. }
  1517. });
  1518.  
  1519. // Setup hotkey options and additional config
  1520. const extraSettings = `
  1521. <div class="advanced-section">
  1522. <div class="control-item toggle-container">
  1523. <input type="checkbox" id="enableHotkeys" name="enableHotkeys" class="toggle-input" checked>
  1524. <label for="enableHotkeys" class="toggle-label">
  1525. <span class="toggle-button"></span>
  1526. <span class="toggle-text">Enable keyboard shortcuts</span>
  1527. </label>
  1528. </div>
  1529.  
  1530. <div class="control-item toggle-container">
  1531. <input type="checkbox" id="randomizeTiming" name="randomizeTiming" class="toggle-input" checked>
  1532. <label for="randomizeTiming" class="toggle-label">
  1533. <span class="toggle-button"></span>
  1534. <span class="toggle-text">Randomize thinking time</span>
  1535. </label>
  1536. </div>
  1537.  
  1538. <div class="style-slider-container">
  1539. <label for="mouseMovementSlider">Mouse Movement Realism:</label>
  1540. <input type="range" id="mouseMovementSlider" min="1" max="10" value="7" class="style-slider">
  1541. <span id="mouseMovementSliderValue">7</span>
  1542. </div>
  1543.  
  1544. <div class="profile-selection">
  1545. <label for="playingProfileSelect">Playing Profile:</label>
  1546. <select id="playingProfileSelect" class="select-input">
  1547. <option value="custom">Custom Settings</option>
  1548. <option value="beginner">Beginner (≈800)</option>
  1549. <option value="intermediate">Intermediate (≈1200)</option>
  1550. <option value="advanced">Advanced (≈1600)</option>
  1551. <option value="expert">Expert (≈2000)</option>
  1552. <option value="master">Master (≈2400+)</option>
  1553. </select>
  1554. </div>
  1555. </div>
  1556. `;
  1557.  
  1558. $('#advanced-settings .advanced-controls').append(extraSettings);
  1559.  
  1560. // Initialize additional settings
  1561. myVars.enableHotkeys = true;
  1562. myVars.randomizeTiming = true;
  1563. myVars.mouseMovementRealism = 0.7;
  1564.  
  1565. // Setup additional event handlers
  1566. $('#enableHotkeys').on('change', function() {
  1567. myVars.enableHotkeys = $(this).prop('checked');
  1568. });
  1569.  
  1570. $('#randomizeTiming').on('change', function() {
  1571. myVars.randomizeTiming = $(this).prop('checked');
  1572. });
  1573.  
  1574. $('#mouseMovementSlider').on('input', function() {
  1575. const value = $(this).val();
  1576. $('#mouseMovementSliderValue').text(value);
  1577. myVars.mouseMovementRealism = parseFloat(value) / 10;
  1578. });
  1579.  
  1580. $('#playingProfileSelect').on('change', function() {
  1581. const profile = $(this).val();
  1582.  
  1583. if (profile !== 'custom') {
  1584. // Preset profiles with appropriate settings
  1585. switch(profile) {
  1586. case 'beginner':
  1587. $('#depthSlider').val(3).trigger('input');
  1588. $('#blunderRateSlider').val(7).trigger('input');
  1589. $('#aggressiveSlider').val(Math.floor(3 + Math.random() * 5)).trigger('input');
  1590. $('#tacticalSlider').val(3).trigger('input');
  1591. break;
  1592. case 'intermediate':
  1593. $('#depthSlider').val(6).trigger('input');
  1594. $('#blunderRateSlider').val(5).trigger('input');
  1595. $('#tacticalSlider').val(5).trigger('input');
  1596. break;
  1597. case 'advanced':
  1598. $('#depthSlider').val(9).trigger('input');
  1599. $('#blunderRateSlider').val(3).trigger('input');
  1600. $('#tacticalSlider').val(7).trigger('input');
  1601. break;
  1602. case 'expert':
  1603. $('#depthSlider').val(12).trigger('input');
  1604. $('#blunderRateSlider').val(2).trigger('input');
  1605. $('#tacticalSlider').val(8).trigger('input');
  1606. $('#positionalSlider').val(8).trigger('input');
  1607. break;
  1608. case 'master':
  1609. $('#depthSlider').val(15).trigger('input');
  1610. $('#blunderRateSlider').val(1).trigger('input');
  1611. $('#tacticalSlider').val(9).trigger('input');
  1612. $('#positionalSlider').val(9).trigger('input');
  1613. break;
  1614. }
  1615. }
  1616. });
  1617.  
  1618. // Add CSS for new elements
  1619. const extraStyles = document.createElement('style');
  1620. extraStyles.innerHTML = `
  1621. .advanced-section {
  1622. margin-top: 15px;
  1623. padding-top: 15px;
  1624. border-top: 1px solid #313244;
  1625. }
  1626.  
  1627. .profile-selection {
  1628. margin-top: 15px;
  1629. }
  1630.  
  1631. .playStyle-controls, .advanced-controls {
  1632. display: flex;
  1633. flex-direction: column;
  1634. gap: 12px;
  1635. }
  1636.  
  1637. .style-slider-container {
  1638. display: flex;
  1639. align-items: center;
  1640. gap: 10px;
  1641. }
  1642.  
  1643. .style-slider-container label {
  1644. font-size: 13px;
  1645. color: #cdd6f4;
  1646. width: 120px;
  1647. }
  1648.  
  1649. .style-slider {
  1650. flex: 1;
  1651. height: 6px;
  1652. -webkit-appearance: none;
  1653. appearance: none;
  1654. background: #313244;
  1655. border-radius: 3px;
  1656. outline: none;
  1657. }
  1658.  
  1659. .style-slider::-webkit-slider-thumb {
  1660. -webkit-appearance: none;
  1661. appearance: none;
  1662. width: 14px;
  1663. height: 14px;
  1664. border-radius: 50%;
  1665. background: #89b4fa;
  1666. cursor: pointer;
  1667. }
  1668.  
  1669. .style-slider-container span {
  1670. font-size: 14px;
  1671. font-weight: 500;
  1672. color: #89b4fa;
  1673. width: 20px;
  1674. text-align: center;
  1675. }
  1676.  
  1677. .highlight-color-picker {
  1678. display: flex;
  1679. align-items: center;
  1680. gap: 10px;
  1681. margin-top: 10px;
  1682. }
  1683.  
  1684. .highlight-color-picker label {
  1685. font-size: 13px;
  1686. color: #cdd6f4;
  1687. }
  1688.  
  1689. .color-input {
  1690. -webkit-appearance: none;
  1691. width: 30px;
  1692. height: 30px;
  1693. border: none;
  1694. border-radius: 50%;
  1695. background: none;
  1696. cursor: pointer;
  1697. }
  1698.  
  1699. .color-input::-webkit-color-swatch {
  1700. border: none;
  1701. border-radius: 50%;
  1702. box-shadow: 0 0 0 2px #45475a;
  1703. }
  1704.  
  1705. .opening-selection {
  1706. display: flex;
  1707. align-items: center;
  1708. gap: 10px;
  1709. margin-top: 10px;
  1710. }
  1711.  
  1712. .opening-selection label {
  1713. font-size: 13px;
  1714. color: #cdd6f4;
  1715. }
  1716.  
  1717. .select-input {
  1718. flex: 1;
  1719. background: #313244;
  1720. border: 1px solid #45475a;
  1721. border-radius: 6px;
  1722. color: #cdd6f4;
  1723. padding: 8px 10px;
  1724. font-size: 14px;
  1725. transition: border-color 0.3s;
  1726. }
  1727.  
  1728. .select-input:focus {
  1729. outline: none;
  1730. border-color: #89b4fa;
  1731. }
  1732. `;
  1733. document.head.appendChild(extraStyles);
  1734.  
  1735. // Load saved settings before applying them to the UI
  1736. myFunctions.loadSettings();
  1737.  
  1738. // Apply loaded settings to UI controls
  1739. $('#autoRun').prop('checked', myVars.autoRun);
  1740. $('#autoMove').prop('checked', myVars.autoMove);
  1741.  
  1742. $('#depthSlider').val(lastValue);
  1743. $('#depthValue').text(lastValue);
  1744. $('#depthText').html("Current Depth: <strong>" + lastValue + "</strong>");
  1745.  
  1746. if (myVars.highlightColor) {
  1747. $('#highlightColor').val(myVars.highlightColor);
  1748. }
  1749.  
  1750. // Update the play style sliders with saved values
  1751. if (myVars.playStyle) {
  1752. $('#aggressiveSlider').val(Math.round(((myVars.playStyle.aggressive - 0.3) / 0.5) * 10));
  1753. $('#aggressiveValue').text($('#aggressiveSlider').val());
  1754.  
  1755. $('#defensiveSlider').val(Math.round(((myVars.playStyle.defensive - 0.3) / 0.5) * 10));
  1756. $('#defensiveValue').text($('#defensiveSlider').val());
  1757.  
  1758. $('#tacticalSlider').val(Math.round(((myVars.playStyle.tactical - 0.2) / 0.6) * 10));
  1759. $('#tacticalValue').text($('#tacticalSlider').val());
  1760.  
  1761. $('#positionalSlider').val(Math.round(((myVars.playStyle.positional - 0.2) / 0.6) * 10));
  1762. $('#positionalValue').text($('#positionalSlider').val());
  1763. }
  1764.  
  1765. // Update blunder rate slider with saved value
  1766. if (myVars.blunderRate !== undefined) {
  1767. $('#blunderRateSlider').val(Math.round(myVars.blunderRate * 10));
  1768. $('#blunderRateValue').text($('#blunderRateSlider').val());
  1769. }
  1770.  
  1771. // Set advanced settings based on saved values
  1772. $('#adaptToRating').prop('checked', myVars.adaptToRating);
  1773. $('#useOpeningBook').prop('checked', myVars.useOpeningBook);
  1774. $('#enableHotkeys').prop('checked', myVars.enableHotkeys);
  1775. $('#randomizeTiming').prop('checked', myVars.randomizeTiming);
  1776.  
  1777. if (myVars.mouseMovementRealism !== undefined) {
  1778. $('#mouseMovementSlider').val(Math.round(myVars.mouseMovementRealism * 10));
  1779. $('#mouseMovementSliderValue').text($('#mouseMovementSlider').val());
  1780. }
  1781.  
  1782. if (myVars.preferredOpenings && myVars.preferredOpenings.length === 1) {
  1783. $('#preferredOpeningSelect').val(myVars.preferredOpenings[0]);
  1784. }
  1785.  
  1786. // Add event handlers to save settings when they change
  1787. $('#autoRun, #autoMove, #adaptToRating, #useOpeningBook, #enableHotkeys, #randomizeTiming').on('change', function() {
  1788. const id = $(this).attr('id');
  1789. myVars[id] = $(this).prop('checked');
  1790. myFunctions.saveSettings();
  1791. });
  1792.  
  1793. $('#depthSlider').on('input', function() {
  1794. // The existing handler already updates the UI
  1795. myFunctions.saveSettings();
  1796. });
  1797.  
  1798. $('#timeDelayMin, #timeDelayMax').on('change', function() {
  1799. myFunctions.saveSettings();
  1800. });
  1801.  
  1802. $('.style-slider').on('input', function() {
  1803. // The existing handler updates the playStyle object
  1804. myFunctions.saveSettings();
  1805. });
  1806.  
  1807. $('#highlightColor').on('input', function() {
  1808. // Existing handler already updates myVars.highlightColor
  1809. myFunctions.saveSettings();
  1810. });
  1811.  
  1812. $('#preferredOpeningSelect').on('change', function() {
  1813. // Existing handler updates preferredOpenings
  1814. myFunctions.saveSettings();
  1815. });
  1816.  
  1817. $('#playingProfileSelect').on('change', function() {
  1818. // After profile is applied
  1819. setTimeout(myFunctions.saveSettings, 100);
  1820. });
  1821.  
  1822. $('#autoMove').on('change', function() {
  1823. myVars.autoMove = $(this).prop('checked');
  1824. console.log(`Auto move set to: ${myVars.autoMove}`);
  1825. myFunctions.saveSettings();
  1826. });
  1827.  
  1828. loaded = true;
  1829. } catch (error) {console.log(error)}
  1830. }
  1831.  
  1832.  
  1833. function other(delay) {
  1834. // Create more natural timing pattern based on game situation
  1835. const gamePhase = estimateGamePhase();
  1836. const positionComplexity = estimatePositionComplexity();
  1837.  
  1838. // Apply more realistic timing adjustments
  1839. let naturalDelay = delay;
  1840.  
  1841. // Faster moves in openings
  1842. if (gamePhase < 10) {
  1843. naturalDelay *= (0.6 + Math.random() * 0.4);
  1844. }
  1845.  
  1846. // Slower in complex positions
  1847. if (positionComplexity > 0.7) {
  1848. naturalDelay *= (1 + Math.random() * 1.5);
  1849. }
  1850.  
  1851. // Add slight additional randomness
  1852. naturalDelay *= (0.85 + Math.random() * 0.3);
  1853.  
  1854. var endTime = Date.now() + naturalDelay;
  1855. var timer = setInterval(()=>{
  1856. if(Date.now() >= endTime){
  1857. myFunctions.autoRun(getAdjustedDepth());
  1858. canGo = true;
  1859. clearInterval(timer);
  1860. }
  1861. },10);
  1862. }
  1863.  
  1864. function getAdjustedDepth() {
  1865. // Get time remaining and adjust depth accordingly
  1866. const timeRemaining = estimateTimeRemaining();
  1867. const gamePhase = estimateGamePhase();
  1868. const positionType = analyzePositionType(board.game.getFEN());
  1869. const isPositionCritical = isPositionCriticalNow();
  1870. // Base depth from slider
  1871. let baseDepth = lastValue;
  1872. // Time-based adjustments
  1873. if (timeRemaining < 30) {
  1874. // Below 30 seconds - use very low depth
  1875. return Math.floor(Math.random() * 3) + 1; // 1-3
  1876. } else if (timeRemaining < 60) {
  1877. // Below 1 minute - use low depth
  1878. return Math.floor(Math.random() * 3) + 5; // 5-7
  1879. }
  1880. // Game phase adjustments
  1881. if (gamePhase < 10) {
  1882. // Opening phase - use lower depth
  1883. baseDepth = Math.min(baseDepth, 10);
  1884. } else if (gamePhase > 30) {
  1885. // Endgame - can use higher depth as positions are simpler
  1886. baseDepth = Math.min(baseDepth + 2, 20);
  1887. }
  1888. // Occasionally use very low depth to prevent detection
  1889. if (!isPositionCritical && Math.random() < 0.15) {
  1890. return Math.floor(Math.random() * 2) + 2; // 2-3
  1891. }
  1892. // Add some randomness to the depth
  1893. const variation = Math.floor(Math.random() * 5) - 2; // -2 to +2
  1894. return Math.max(1, Math.min(20, baseDepth + variation));
  1895. }
  1896.  
  1897. function isPositionCriticalNow() {
  1898. // Determine if the current position is critical
  1899. // This is a simplified implementation
  1900. try {
  1901. // Check if kings are under attack
  1902. const inCheck = board.game.inCheck();
  1903. // Check material balance (simplified)
  1904. const fen = board.game.getFEN();
  1905. const whiteMaterial = countMaterial(fen, true);
  1906. const blackMaterial = countMaterial(fen, false);
  1907. const materialDifference = Math.abs(whiteMaterial - blackMaterial);
  1908. // Position is critical if in check or material is close
  1909. return inCheck || materialDifference < 2;
  1910. } catch (e) {
  1911. return false;
  1912. }
  1913. }
  1914.  
  1915. function countMaterial(fen, isWhite) {
  1916. // Simple material counting function
  1917. const position = fen.split(' ')[0];
  1918. let material = 0;
  1919. const pieces = isWhite ? 'PNBRQK' : 'pnbrqk';
  1920. const values = { 'P': 1, 'N': 3, 'B': 3, 'R': 5, 'Q': 9, 'K': 0,
  1921. 'p': 1, 'n': 3, 'b': 3, 'r': 5, 'q': 9, 'k': 0 };
  1922. for (let char of position) {
  1923. if (pieces.includes(char)) {
  1924. material += values[char];
  1925. }
  1926. }
  1927. return material;
  1928. }
  1929.  
  1930. async function getVersion(){
  1931. var GF = new GreasyFork; // set upping api
  1932. var code = await GF.get().script().code(531100); // Get code
  1933. var version = GF.parseScriptCodeMeta(code).filter(e => e.meta === '@version')[0].value; // filtering array and getting value of @version
  1934.  
  1935. if(currentVersion !== version){
  1936. while(true){
  1937. alert('UPDATE THIS SCRIPT IN ORDER TO PROCEED!');
  1938. }
  1939. }
  1940. }
  1941.  
  1942. //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.
  1943. //getVersion();
  1944.  
  1945. const waitForChessBoard = setInterval(() => {
  1946. if(loaded) {
  1947. board = $('chess-board')[0] || $('wc-chess-board')[0];
  1948. myVars.autoRun = $('#autoRun')[0].checked;
  1949. myVars.autoMove = $('#autoMove')[0].checked;
  1950. let minDel = parseFloat($('#timeDelayMin')[0].value);
  1951. let maxDel = parseFloat($('#timeDelayMax')[0].value);
  1952. myVars.delay = Math.random() * (maxDel - minDel) + minDel;
  1953. myVars.isThinking = isThinking;
  1954. myFunctions.spinner();
  1955. if(board.game.getTurn() == board.game.getPlayingAs()){myTurn = true;} else {myTurn = false;}
  1956. $('#depthText')[0].innerHTML = "Current Depth: <strong>"+lastValue+"</strong>";
  1957. } else {
  1958. myFunctions.loadEx();
  1959. }
  1960.  
  1961.  
  1962. if(!engine.engine){
  1963. myFunctions.loadChessEngine();
  1964. }
  1965. if(myVars.autoRun == true && canGo == true && isThinking == false && myTurn){
  1966. //console.log(`going: ${canGo} ${isThinking} ${myTurn}`);
  1967. canGo = false;
  1968. var currentDelay = myVars.delay != undefined ? myVars.delay * 1000 : 10;
  1969. other(currentDelay);
  1970. }
  1971. }, 100);
  1972.  
  1973. // Add these two functions for saving and loading settings
  1974. myFunctions.saveSettings = function() {
  1975. GM_setValue('autoRun', myVars.autoRun);
  1976. GM_setValue('autoMove', myVars.autoMove);
  1977. GM_setValue('timeDelayMin', $('#timeDelayMin').val());
  1978. GM_setValue('timeDelayMax', $('#timeDelayMax').val());
  1979. GM_setValue('depthValue', lastValue);
  1980. GM_setValue('highlightColor', myVars.highlightColor);
  1981. GM_setValue('playStyle', myVars.playStyle);
  1982. GM_setValue('blunderRate', myVars.blunderRate);
  1983. GM_setValue('adaptToRating', myVars.adaptToRating);
  1984. GM_setValue('useOpeningBook', myVars.useOpeningBook);
  1985. GM_setValue('preferredOpenings', myVars.preferredOpenings);
  1986. GM_setValue('enableHotkeys', myVars.enableHotkeys);
  1987. GM_setValue('randomizeTiming', myVars.randomizeTiming);
  1988. GM_setValue('mouseMovementRealism', myVars.mouseMovementRealism);
  1989. myFunctions.saveGameMemory(result, opponent, mistakes);
  1990. myVars.openingRepertoire = GM_getValue('openingRepertoire', {
  1991. white: {
  1992. main: getRandomOpenings(2),
  1993. experimental: getRandomOpenings(3, true),
  1994. success: {}
  1995. },
  1996. black: {
  1997. responses: {
  1998. e4: getRandomResponses('e4', 2),
  1999. d4: getRandomResponses('d4', 2),
  2000. c4: getRandomResponses('c4', 2),
  2001. other: getRandomResponses('other', 2)
  2002. },
  2003. success: {}
  2004. },
  2005. lastUpdated: Date.now()
  2006. });
  2007. updateOpeningRepertoire();
  2008. };
  2009.  
  2010. myFunctions.loadSettings = function() {
  2011. myVars.autoRun = GM_getValue('autoRun', false);
  2012. myVars.autoMove = GM_getValue('autoMove', false);
  2013. $('#timeDelayMin').val(GM_getValue('timeDelayMin', 0.1));
  2014. $('#timeDelayMax').val(GM_getValue('timeDelayMax', 1));
  2015. lastValue = GM_getValue('depthValue', 11);
  2016. myVars.highlightColor = GM_getValue('highlightColor', 'rgb(235, 97, 80)');
  2017. myVars.playStyle = GM_getValue('playStyle', {
  2018. aggressive: Math.random() * 0.5 + 0.3,
  2019. defensive: Math.random() * 0.5 + 0.3,
  2020. tactical: Math.random() * 0.6 + 0.2,
  2021. positional: Math.random() * 0.6 + 0.2
  2022. });
  2023. myVars.blunderRate = GM_getValue('blunderRate', 0.05);
  2024. myVars.adaptToRating = GM_getValue('adaptToRating', true);
  2025. myVars.useOpeningBook = GM_getValue('useOpeningBook', true);
  2026. myVars.preferredOpenings = GM_getValue('preferredOpenings', ["e4", "d4", "c4", "Nf3"]);
  2027. myVars.enableHotkeys = GM_getValue('enableHotkeys', true);
  2028. myVars.randomizeTiming = GM_getValue('randomizeTiming', true);
  2029. myVars.mouseMovementRealism = GM_getValue('mouseMovementRealism', 0.7);
  2030. };
  2031.  
  2032. myFunctions.saveGameMemory = function(result, opponent, mistakes) {
  2033. // Get existing memory
  2034. let gameMemory = GM_getValue('gameMemory', {
  2035. openingSuccess: {},
  2036. opponentHistory: {},
  2037. mistakePositions: []
  2038. });
  2039.  
  2040. // Store opening success rate
  2041. const opening = board.game.pgn.split('\n\n')[1].split(' ').slice(0, 6).join(' ');
  2042. if (!gameMemory.openingSuccess[opening]) {
  2043. gameMemory.openingSuccess[opening] = { wins: 0, losses: 0, draws: 0 };
  2044. }
  2045. gameMemory.openingSuccess[opening][result]++;
  2046.  
  2047. // Record opponent data
  2048. if (!gameMemory.opponentHistory[opponent]) {
  2049. gameMemory.opponentHistory[opponent] = { games: 0, style: 'unknown' };
  2050. }
  2051. gameMemory.opponentHistory[opponent].games++;
  2052.  
  2053. // Store mistake patterns for future reference
  2054. if (mistakes && mistakes.length) {
  2055. gameMemory.mistakePositions = gameMemory.mistakePositions.concat(mistakes).slice(-50);
  2056. }
  2057.  
  2058. GM_setValue('gameMemory', gameMemory);
  2059. };
  2060.  
  2061. function getThinkingTime(position) {
  2062. const baseTime = parseFloat($('#timeDelayMin').val()) * 1000;
  2063. const maxTime = parseFloat($('#timeDelayMax').val()) * 1000;
  2064.  
  2065. // Analyze position
  2066. const complexity = calculatePositionComplexity(position); // 0-1
  2067. const criticalness = determinePositionCriticalness(position); // 0-1
  2068. const familiarity = assessPositionFamiliarity(position); // 0-1
  2069.  
  2070. // Human-like time scaling
  2071. let thinkingTime = baseTime;
  2072.  
  2073. // Complex positions take more time
  2074. thinkingTime += complexity * (maxTime - baseTime) * 0.7;
  2075.  
  2076. // Critical positions deserve more attention
  2077. thinkingTime += criticalness * (maxTime - baseTime) * 0.5;
  2078.  
  2079. // Unfamiliar positions need more thought
  2080. thinkingTime += (1 - familiarity) * (maxTime - baseTime) * 0.3;
  2081.  
  2082. // Avoid predictable timing with small random variation
  2083. thinkingTime *= 0.85 + Math.random() * 0.3;
  2084.  
  2085. return Math.min(maxTime * 1.2, thinkingTime);
  2086. }
  2087.  
  2088. // Add placeholder functions that can be expanded
  2089. function calculatePositionComplexity(position) {
  2090. // Count material, tension, possible tactics
  2091. const pieceCount = position.split(/[prnbqkPRNBQK]/).length - 1;
  2092. const hasQueen = position.includes('q') || position.includes('Q');
  2093. const pawnStructure = analyzeBasicPawnStructure(position);
  2094.  
  2095. return Math.min(1, (pieceCount / 32) + (hasQueen ? 0.2 : 0) + pawnStructure * 0.3);
  2096. }
  2097.  
  2098. function adjustEngineEvaluation(position, move, evaluation) {
  2099. // Apply player's strategic preferences
  2100. const adjustedEval = { ...evaluation };
  2101.  
  2102. // Adjust based on fingerprint
  2103. if (myVars.playerFingerprint.favoredPieces === 'knights' && move.includes('N')) {
  2104. adjustedEval.score += 0.05 + Math.random() * 0.1;
  2105. }
  2106.  
  2107. if (myVars.playerFingerprint.favoredPieces === 'bishops' && move.includes('B')) {
  2108. adjustedEval.score += 0.05 + Math.random() * 0.1;
  2109. }
  2110.  
  2111. // Kingside/queenside attack preference
  2112. if (myVars.playerFingerprint.attackingStyle === 'kingside' && isKingsideMove(move)) {
  2113. adjustedEval.score += 0.07 + Math.random() * 0.08;
  2114. }
  2115.  
  2116. // Occasionally have a "brilliant" insight (1-2% of moves)
  2117. if (Math.random() < 0.015) {
  2118. // Temporary increase in effective depth for this move evaluation
  2119. console.log("Brilliant insight detected!");
  2120. return getDeepEvaluation(position, move);
  2121. }
  2122.  
  2123. return adjustedEval;
  2124. }
  2125.  
  2126. function isEndgame(position) {
  2127. // Basic endgame detection
  2128. const pieceCount = position.split(/[prnbqkPRNBQK]/).length - 1;
  2129. return pieceCount <= 10;
  2130. }
  2131.  
  2132. function adjustEndgamePlay(fen, moves) {
  2133. if (!isEndgame(fen)) return moves;
  2134.  
  2135. // Common human endgame patterns
  2136. const hasKingActivity = increasesKingActivity(moves[0], fen);
  2137. const promotionPotential = evaluatePromotionPotential(fen);
  2138.  
  2139. // King opposition knowledge (common human knowledge)
  2140. if (hasKingOpposition(fen) && Math.random() < 0.9) {
  2141. // Humans typically understand king opposition
  2142. return prioritizeOppositionMoves(moves);
  2143. }
  2144.  
  2145. // Activate king in endgames (humans know this)
  2146. if (hasKingActivity && Math.random() < 0.75) {
  2147. return moves; // Keep the engine's correct evaluation
  2148. } else if (hasKingActivity) {
  2149. // Sometimes miss the importance of king activity
  2150. return [moves[1] || moves[0], ...moves.slice(1)];
  2151. }
  2152.  
  2153. // Humans tend to focus on pawn promotion
  2154. if (promotionPotential > 0.7) {
  2155. return prioritizePawnAdvancement(moves);
  2156. }
  2157.  
  2158. return moves;
  2159. }
  2160.  
  2161. // Add to myVars at initialization
  2162. myVars.psychologicalState = {
  2163. confidence: 0.7 + Math.random() * 0.3, // 0.7-1.0
  2164. tiltFactor: 0, // 0-1, increases with blunders
  2165. focus: 0.8 + Math.random() * 0.2, // 0.8-1.0, decreases with time
  2166. playTime: 0 // tracks continuous play time
  2167. };
  2168.  
  2169. // Update in a function that runs periodically
  2170. function updatePsychologicalState(gameState) {
  2171. // Increase play time
  2172. myVars.psychologicalState.playTime += 1;
  2173.  
  2174. // Focus decreases with time (mental fatigue)
  2175. if (myVars.psychologicalState.playTime > 10) {
  2176. myVars.psychologicalState.focus = Math.max(0.5,
  2177. myVars.psychologicalState.focus - 0.01);
  2178. }
  2179.  
  2180. // Check for blunders in recent moves
  2181. if (detectBlunder(gameState)) {
  2182. // Increase tilt after mistakes
  2183. myVars.psychologicalState.tiltFactor = Math.min(1,
  2184. myVars.psychologicalState.tiltFactor + 0.25);
  2185. myVars.psychologicalState.confidence = Math.max(0.3,
  2186. myVars.psychologicalState.confidence - 0.15);
  2187. }
  2188.  
  2189. // Good moves restore confidence
  2190. if (detectGoodMove(gameState)) {
  2191. myVars.psychologicalState.confidence = Math.min(1,
  2192. myVars.psychologicalState.confidence + 0.05);
  2193. myVars.psychologicalState.tiltFactor = Math.max(0,
  2194. myVars.psychologicalState.tiltFactor - 0.1);
  2195. }
  2196.  
  2197. // Apply psychological state to blunder rate
  2198. const effectiveBlunderRate = myVars.blunderRate *
  2199. (1 + myVars.psychologicalState.tiltFactor) *
  2200. (2 - myVars.psychologicalState.focus);
  2201.  
  2202. return effectiveBlunderRate;
  2203. }
  2204.  
  2205. function detectTimeControl() {
  2206. try {
  2207. // Look for the clock element and determine time control
  2208. const clockEl = document.querySelector('.clock-component');
  2209. if (clockEl) {
  2210. const timeText = clockEl.textContent;
  2211. const minutes = parseInt(timeText.split(':')[0]);
  2212.  
  2213. if (minutes >= 15) return 'classical';
  2214. if (minutes >= 5) return 'rapid';
  2215. return 'blitz';
  2216. }
  2217. } catch (e) {}
  2218.  
  2219. return 'rapid'; // Default
  2220. }
  2221.  
  2222. function adaptToTimeControl() {
  2223. const timeControl = detectTimeControl();
  2224.  
  2225. switch (timeControl) {
  2226. case 'blitz':
  2227. // More intuitive play, faster moves, higher blunder rate
  2228. myVars.blunderRate *= 1.3;
  2229. $('#timeDelayMin').val(Math.max(0.1, parseFloat($('#timeDelayMin').val()) * 0.7));
  2230. $('#timeDelayMax').val(Math.max(0.3, parseFloat($('#timeDelayMax').val()) * 0.7));
  2231. // Use more recognizable patterns and opening theory
  2232. myVars.patternRecognitionWeight = 0.8;
  2233. break;
  2234.  
  2235. case 'rapid':
  2236. // Balanced approach
  2237. myVars.patternRecognitionWeight = 0.6;
  2238. break;
  2239.  
  2240. case 'classical':
  2241. // More calculation, deeper search, fewer blunders
  2242. myVars.blunderRate *= 0.7;
  2243. $('#timeDelayMin').val(parseFloat($('#timeDelayMin').val()) * 1.2);
  2244. $('#timeDelayMax').val(parseFloat($('#timeDelayMax').val()) * 1.3);
  2245. // More unique moves, less reliance on patterns
  2246. myVars.patternRecognitionWeight = 0.4;
  2247. break;
  2248. }
  2249. }
  2250.  
  2251. function updateOpeningRepertoire() {
  2252. // Only update periodically (simulating a player learning new openings)
  2253. if (Date.now() - myVars.openingRepertoire.lastUpdated < 7 * 24 * 60 * 60 * 1000) {
  2254. return; // Only update weekly
  2255. }
  2256.  
  2257. // Replace worst performing opening with a new one
  2258. const gameMemory = GM_getValue('gameMemory', { openingSuccess: {} });
  2259.  
  2260. // Find worst performing opening
  2261. let worstScore = Infinity;
  2262. let worstOpening = null;
  2263.  
  2264. for (const opening in gameMemory.openingSuccess) {
  2265. const stats = gameMemory.openingSuccess[opening];
  2266. const score = stats.wins - stats.losses;
  2267.  
  2268. if (score < worstScore && stats.wins + stats.losses + stats.draws >= 5) {
  2269. worstScore = score;
  2270. worstOpening = opening;
  2271. }
  2272. }
  2273.  
  2274. // Replace it if we found a bad one
  2275. if (worstOpening && worstScore < 0) {
  2276. console.log("Phasing out unprofitable opening: " + worstOpening);
  2277. // Replace with a new experimental opening
  2278. if (worstOpening.startsWith('1.')) {
  2279. // It's a white opening
  2280. myVars.openingRepertoire.white.experimental =
  2281. myVars.openingRepertoire.white.experimental.filter(o => o !== worstOpening);
  2282. myVars.openingRepertoire.white.experimental.push(getRandomOpenings(1, true)[0]);
  2283. } else {
  2284. // It's a black response
  2285. // Implementation would be similar to white
  2286. }
  2287. }
  2288.  
  2289. myVars.openingRepertoire.lastUpdated = Date.now();
  2290. GM_setValue('openingRepertoire', myVars.openingRepertoire);
  2291. }
  2292.  
  2293. // Then when evaluating positions:
  2294. function adjustForTacticalProfile(moves, position) {
  2295. for (let i = 0; i < moves.length; i++) {
  2296. const tacticalMotif = identifyTacticalMotif(moves[i], position);
  2297.  
  2298. // Boost strengths
  2299. if (myVars.tacticalProfile.strengths.includes(tacticalMotif)) {
  2300. // Higher chance of finding this tactic
  2301. if (i > 0 && Math.random() < 0.8) {
  2302. // Swap with the first move (more likely to be played)
  2303. [moves[0], moves[i]] = [moves[i], moves[0]];
  2304. }
  2305. }
  2306.  
  2307. // Miss weaknesses
  2308. if (myVars.tacticalProfile.weaknesses.includes(tacticalMotif)) {
  2309. // Higher chance of missing this tactic
  2310. if (i === 0 && moves.length > 1 && Math.random() < 0.7) {
  2311. // Swap with the second move (less likely to be played)
  2312. [moves[0], moves[1]] = [moves[1], moves[0]];
  2313. }
  2314. }
  2315. }
  2316.  
  2317. return moves;
  2318. }
  2319. }
  2320.  
  2321. //Touching below may break the script
  2322.  
  2323. var isThinking = false
  2324. var canGo = true;
  2325. var myTurn = false;
  2326. var board;
  2327.  
  2328.  
  2329. window.addEventListener("load", (event) => {
  2330. let currentTime = Date.now();
  2331. main();
  2332. });
  2333.  
  2334. function getAppropriateDepth() {
  2335. // Get player's rating if available
  2336. let playerRating = 1500; // Default
  2337. try {
  2338. const ratingEl = document.querySelector('.user-tagline-rating');
  2339. if (ratingEl) {
  2340. playerRating = parseInt(ratingEl.textContent);
  2341. }
  2342. } catch (e) {}
  2343.  
  2344. // Map ratings to appropriate depths
  2345. if (playerRating < 800) return Math.floor(Math.random() * 3) + 1; // 1-3
  2346. if (playerRating < 1200) return Math.floor(Math.random() * 3) + 3; // 3-5
  2347. if (playerRating < 1600) return Math.floor(Math.random() * 3) + 5; // 5-7
  2348. if (playerRating < 2000) return Math.floor(Math.random() * 3) + 7; // 7-9
  2349. if (playerRating < 2400) return Math.floor(Math.random() * 4) + 9; // 9-12
  2350. return Math.floor(Math.random() * 5) + 12; // 12-16
  2351. }
  2352.  
  2353. function getBezierPoint(t, p0, p1, p2, p3) {
  2354. const cX = 3 * (p1.x - p0.x);
  2355. const bX = 3 * (p2.x - p1.x) - cX;
  2356. const aX = p3.x - p0.x - cX - bX;
  2357. const cY = 3 * (p1.y - p0.y);
  2358. const bY = 3 * (p2.y - p1.y) - cY;
  2359. const aY = p3.y - p0.y - cY - bY;
  2360. const x = (aX * Math.pow(t, 3)) + (bX * Math.pow(t, 2)) + (cX * t) + p0.x;
  2361. const y = (aY * Math.pow(t, 3)) + (bY * Math.pow(t, 2)) + (cY * t) + p0.y;
  2362. return { x, y };
  2363. }
  2364.  
  2365. function executeMouseMovement(points, index, delay, callback) {
  2366. if (index >= points.length) {
  2367. if (callback) callback();
  2368. return;
  2369. }
  2370. // Simulate mouse movement
  2371. const point = points[index];
  2372. // In a real implementation, you would trigger actual mouse events
  2373. // For our purposes, we'll just move to the next point
  2374. setTimeout(() => {
  2375. executeMouseMovement(points, index + 1, delay, callback);
  2376. }, delay);
  2377. }
  2378.  
  2379. function getSquarePosition(square) {
  2380. // Convert chess notation (e.g., "e4") to screen coordinates
  2381. // This is a simplified version - in reality, you'd need to get actual board coordinates
  2382. const file = square.charCodeAt(0) - 'a'.charCodeAt(0);
  2383. const rank = parseInt(square.charAt(1)) - 1;
  2384. // Get board dimensions
  2385. const boardRect = board.getBoundingClientRect();
  2386. const squareSize = boardRect.width / 8;
  2387. // Calculate center of the square
  2388. const x = boardRect.left + (file + 0.5) * squareSize;
  2389. const y = boardRect.top + (7 - rank + 0.5) * squareSize;
  2390. return { x, y };
  2391. }