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.

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// additional copyright/license info:
//© All Rights Reserved
//
//Chess.com Enhanced Experience © 2024 by Akashdeep
//
// ==UserScript
// @name         Chess.com UltraX bot with Panel
// @namespace    Akashdeep
// @version      1.0.1.1
// @description  Enhances your Chess.com experience with move suggestions, UI enhancements, and customizable features.  Credits to GoodtimeswithEno for the initial move highlighting and basic chess engine implementation.
// @author       Akashdeep
// @license      Chess.com Enhanced Experience © 2024 by Akashdeep, © All Rights Reserved
// @match       https://www.chess.com/play/*
// @match       https://www.chess.com/game/*
// @match       https://www.chess.com/puzzles/*
// @match       https://www.chess.com/*
// @icon         data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @grant       GM_getResourceText
// @grant       GM_registerMenuCommand
// @resource    stockfish.js        https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.2/stockfish.js
// @require     https://code.jquery.com/jquery-3.6.0.min.js
// @run-at      document-start
// @liscense MIT

// @downloadURL
// @updateURL
// ==/UserScript==
(() => {
  // config.js
  var currentVersion = "1.0.1.1";
  function getRandomTacticalStrength() {
    const strengths = [
      "fork",
      "pin",
      "skewer",
      "discovery",
      "zwischenzug",
      "removing-defender",
      "attraction"
    ];
    return strengths[Math.floor(Math.random() * strengths.length)];
  }
  function getRandomTacticalWeakness() {
    const weaknesses = [
      "long-calculation",
      "quiet-moves",
      "backward-moves",
      "zugzwang",
      "prophylaxis",
      "piece-coordination"
    ];
    return weaknesses[Math.floor(Math.random() * weaknesses.length)];
  }

  // variables.js
  function initializeVariables() {
    const myVars = {
      autoMovePiece: false,
      autoRun: false,
      delay: 0.1,
      loaded: false,
      lastValue: 11,
      playStyle: {
        aggressive: Math.random() * 0.5 + 0.3,
        // 0.3-0.8 tendency for aggressive moves
        defensive: Math.random() * 0.5 + 0.3,
        // 0.3-0.8 tendency for defensive moves
        tactical: Math.random() * 0.6 + 0.2,
        // 0.2-0.8 tendency for tactical moves
        positional: Math.random() * 0.6 + 0.2
        // 0.2-0.8 tendency for positional moves
      },
      preferredOpenings: [
        "e4",
        "d4",
        "c4",
        "Nf3"
        // Just examples, could be expanded
      ].sort(() => Math.random() - 0.5),
      // Randomize the order
      playerFingerprint: GM_getValue("playerFingerprint", {
        favoredPieces: Math.random() < 0.5 ? "knights" : "bishops",
        openingTempo: Math.random() * 0.5 + 0.5,
        // 0.5-1.0 opening move speed
        tacticalAwareness: Math.random() * 0.4 + 0.6,
        // 0.6-1.0 tactical vision
        exchangeThreshold: Math.random() * 0.3 + 0.1,
        // When to accept exchanges
        attackingStyle: ["kingside", "queenside", "central"][Math.floor(Math.random() * 3)]
      }),
      tacticalProfile: GM_getValue("tacticalProfile", {
        strengths: [
          getRandomTacticalStrength(),
          getRandomTacticalStrength()
        ],
        weaknesses: [
          getRandomTacticalWeakness(),
          getRandomTacticalWeakness()
        ]
      }),
      psychologicalState: {
        confidence: 0.7 + Math.random() * 0.3,
        // 0.7-1.0
        tiltFactor: 0,
        // 0-1, increases with blunders
        focus: 0.8 + Math.random() * 0.2,
        // 0.8-1.0, decreases with time
        playTime: 0
        // tracks continuous play time
      }
    };
    if (!GM_getValue("playerFingerprint")) {
      GM_setValue("playerFingerprint", myVars.playerFingerprint);
    }
    if (!GM_getValue("tacticalProfile")) {
      GM_setValue("tacticalProfile", myVars.tacticalProfile);
    }
    return myVars;
  }

  // engine.js
  function setupEngine(myVars, myFunctions) {
    const engine = {
      engine: null
    };
    myFunctions.loadChessEngine = function() {
      if (!engine.stockfishObjectURL) {
        engine.stockfishObjectURL = URL.createObjectURL(new Blob([GM_getResourceText("stockfish.js")], { type: "application/javascript" }));
      }
      console.log(engine.stockfishObjectURL);
      if (engine.stockfishObjectURL) {
        engine.engine = new Worker(engine.stockfishObjectURL);
        engine.engine.onmessage = (e) => {
          myFunctions.parser(e);
        };
        engine.engine.onerror = (e) => {
          console.log("Worker Error: " + e);
        };
        engine.engine.postMessage("ucinewgame");
      }
      console.log("loaded chess engine");
    };
    myFunctions.reloadChessEngine = function() {
      console.log(`Reloading the chess engine!`);
      engine.engine.terminate();
      window.isThinking = false;
      myFunctions.loadChessEngine();
    };
    myFunctions.runChessEngine = function(depth) {
      var adjustedDepth = myFunctions.getAdjustedDepth();
      var fen = window.board.game.getFEN();
      var positionType = myFunctions.analyzePositionType(fen);
      console.log(`Original depth: ${depth}, Adjusted for time/position: ${adjustedDepth}`);
      engine.engine.postMessage(`position fen ${fen}`);
      console.log(`updated: position fen ${fen}`);
      window.isThinking = true;
      if (depth >= 15) {
        engine.engine.postMessage(`setoption name MultiPV value 5`);
      } else {
        engine.engine.postMessage(`setoption name MultiPV value 1`);
      }
      engine.engine.postMessage(`go depth ${adjustedDepth}`);
      myVars.lastValue = depth;
    };
    myFunctions.autoRun = function(lstValue) {
      if (window.board.game.getTurn() == window.board.game.getPlayingAs()) {
        myFunctions.runChessEngine(lstValue);
      }
    };
    return engine;
  }

  // ui/html.js
  var mainTemplate = `
<div class="chess-bot-container">
    <div class="bot-header">
        <div class="bot-logo">
            <svg viewBox="0 0 24 24" width="24" height="24">
                <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" />
            </svg>
        </div>
        <h3 class="bot-title">Panel Pro By @akashdeep</h3>
        <div id="thinking-indicator" class="thinking-indicator">
            <span class="dot dot1"></span>
            <span class="dot dot2"></span>
            <span class="dot dot3"></span>
        </div>
    </div>

    <div class="bot-tabs">
        <button class="tab-button active" data-tab="main-settings">Main</button>
        <button class="tab-button" data-tab="style-settings">Play Style</button>
        <button class="tab-button" data-tab="advanced-settings">Advanced</button>
    </div>

    <div class="bot-tabs-content">
        <div class="tab-content active" id="main-settings">
            <div class="bot-info">
                <div class="depth-card">
                    <p id="depthText" class="depth-display">Current Depth: <strong>11</strong></p>
                    <p class="key-hint">Press a key (Q-Z) to change depth</p>

                    <div class="depth-control">
                        <label for="depthSlider">Depth/ELO:</label>
                        <div class="slider-controls">
                            <button class="depth-button" id="decreaseDepth">-</button>
                            <input type="range" id="depthSlider" min="1" max="21" value="11" class="depth-slider">
                            <button class="depth-button" id="increaseDepth">+</button>
                        </div>
                        <span id="depthValue">11</span>
                    </div>
                </div>
            </div>

            <div class="bot-controls">
                <div class="control-group">
                    <div class="control-item toggle-container">
                        <input type="checkbox" id="autoRun" name="autoRun" class="toggle-input" value="false">
                        <label for="autoRun" class="toggle-label">
                            <span class="toggle-button"></span>
                            <span class="toggle-text">Auto Run</span>
                        </label>
                    </div>

                    <div class="control-item toggle-container">
                        <input type="checkbox" id="autoMove" name="autoMove" class="toggle-input" value="false">
                        <label for="autoMove" class="toggle-label">
                            <span class="toggle-button"></span>
                            <span class="toggle-text">Auto Move</span>
                        </label>
                    </div>
                </div>

                <div class="control-group">
                    <div class="control-item slider-container">
                        <label for="timeDelayMin">Min Delay (sec)</label>
                        <input type="number" id="timeDelayMin" name="timeDelayMin" min="0.1" value="0.1" step="0.1" class="number-input">
                    </div>

                    <div class="control-item slider-container">
                        <label for="timeDelayMax">Max Delay (sec)</label>
                        <input type="number" id="timeDelayMax" name="timeDelayMax" min="0.1" value="1" step="0.1" class="number-input">
                    </div>
                </div>
            </div>
        </div>

        <div class="tab-content" id="style-settings">
            <div class="playStyle-controls">
                <h4 class="settings-section-title">Playing Style Settings</h4>

                <div class="style-slider-container">
                    <label for="aggressiveSlider">Aggressive Play:</label>
                    <input type="range" id="aggressiveSlider" min="1" max="10" value="5" class="style-slider">
                    <span id="aggressiveValue">5</span>
                </div>

                <div class="style-slider-container">
                    <label for="defensiveSlider">Defensive Play:</label>
                    <input type="range" id="defensiveSlider" min="1" max="10" value="5" class="style-slider">
                    <span id="defensiveValue">5</span>
                </div>

                <div class="style-slider-container">
                    <label for="tacticalSlider">Tactical Play:</label>
                    <input type="range" id="tacticalSlider" min="1" max="10" value="5" class="style-slider">
                    <span id="tacticalValue">5</span>
                </div>

                <div class="style-slider-container">
                    <label for="positionalSlider">Positional Play:</label>
                    <input type="range" id="positionalSlider" min="1" max="10" value="5" class="style-slider">
                    <span id="positionalValue">5</span>
                </div>

                <div class="style-slider-container">
                    <label for="blunderRateSlider">Blunder Rate:</label>
                    <input type="range" id="blunderRateSlider" min="0" max="10" value="2" class="style-slider">
                    <span id="blunderRateValue">2</span>
                </div>
            </div>
        </div>

        <div class="tab-content" id="advanced-settings">
            <div class="advanced-controls">
                <h4 class="settings-section-title">Advanced Settings</h4>

                <div class="control-item toggle-container">
                    <input type="checkbox" id="adaptToRating" name="adaptToRating" class="toggle-input" value="true" checked>
                    <label for="adaptToRating" class="toggle-label">
                        <span class="toggle-button"></span>
                        <span class="toggle-text">Adapt to opponent rating</span>
                    </label>
                </div>

                <div class="control-item toggle-container">
                    <input type="checkbox" id="useOpeningBook" name="useOpeningBook" class="toggle-input" value="true" checked>
                    <label for="useOpeningBook" class="toggle-label">
                        <span class="toggle-button"></span>
                        <span class="toggle-text">Use personalized openings</span>
                    </label>
                </div>

                <div class="highlight-color-picker">
                    <label for="highlightColor">Move highlight color:</label>
                    <input type="color" id="highlightColor" value="#eb6150" class="color-input">
                </div>

                <div class="opening-selection">
                    <label for="preferredOpeningSelect">Preferred Opening:</label>
                    <select id="preferredOpeningSelect" class="select-input">
                        <option value="random">Random</option>
                        <option value="e4">e4 (King's Pawn)</option>
                        <option value="d4">d4 (Queen's Pawn)</option>
                        <option value="c4">c4 (English)</option>
                        <option value="Nf3">Nf3 (R\xE9ti)</option>
                    </select>
                </div>
            </div>
        </div>
    </div>

    <div class="bot-actions">
        <button type="button" id="relEngBut" class="action-button primary-button" onclick="document.myFunctions.reloadChessEngine()">
            <svg viewBox="0 0 24 24" width="16" height="16">
                <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" />
            </svg>
            Reload Engine
        </button>

        <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/egsakash/chess.comPanelPro/issues' : console.log('canceled')">
            <svg viewBox="0 0 24 24" width="16" height="16">
                <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" />
            </svg>
            Report Issue
        </button>
    </div>
</div>`;
  var advancedSettingsTemplate = `
<div class="advanced-section">
    <div class="control-item toggle-container">
        <input type="checkbox" id="enableHotkeys" name="enableHotkeys" class="toggle-input" checked>
        <label for="enableHotkeys" class="toggle-label">
            <span class="toggle-button"></span>
            <span class="toggle-text">Enable keyboard shortcuts</span>
        </label>
    </div>

    <div class="control-item toggle-container">
        <input type="checkbox" id="randomizeTiming" name="randomizeTiming" class="toggle-input" checked>
        <label for="randomizeTiming" class="toggle-label">
            <span class="toggle-button"></span>
            <span class="toggle-text">Randomize thinking time</span>
        </label>
    </div>

    <div class="style-slider-container">
        <label for="mouseMovementSlider">Mouse Movement Realism:</label>
        <input type="range" id="mouseMovementSlider" min="1" max="10" value="7" class="style-slider">
        <span id="mouseMovementSliderValue">7</span>
    </div>

    <div class="profile-selection">
        <label for="playingProfileSelect">Playing Profile:</label>
        <select id="playingProfileSelect" class="select-input">
            <option value="custom">Custom Settings</option>
            <option value="beginner">Beginner (\u2248800)</option>
            <option value="intermediate">Intermediate (\u22481200)</option>
            <option value="advanced">Advanced (\u22481600)</option>
            <option value="expert">Expert (\u22482000)</option>
            <option value="master">Master (\u22482400+)</option>
        </select>
    </div>
</div>
`;
  var spinnerTemplate = `
<div style="display:none;" id="overlay">
    <div style="
        margin: 0 auto;
        height: 40px;
        width: 40px;
        animation: rotate 0.8s infinite linear;
        border: 4px solid #89b4fa;
        border-right-color: transparent;
        border-radius: 50%;
        box-shadow: 0 0 10px rgba(137, 180, 250, 0.4);
    "></div>
</div>
`;

  // ui/styles.js
  var mainStyles = `
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');

#settingsContainer {
    background-color: #1e1e2e;
    color: #cdd6f4;
    border-radius: 12px;
    padding: 20px;
    margin-top: 15px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.3);
    font-family: 'Roboto', sans-serif;
    max-width: 400px;
    margin-left: auto;
    margin-right: auto;
    border: 1px solid #313244;
}

.chess-bot-container {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.bot-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 5px;
    position: relative;
}

.bot-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #89b4fa;
}

.bot-title {
    margin: 0;
    color: #89b4fa;
    font-size: 20px;
    font-weight: 500;
    letter-spacing: 0.5px;
}

.thinking-indicator {
    position: absolute;
    right: 0;
    display: none;
    align-items: center;
}

.thinking-indicator.active {
    display: flex;
}

.dot {
    width: 8px;
    height: 8px;
    margin: 0 2px;
    background-color: #89b4fa;
    border-radius: 50%;
    opacity: 0.6;
}

.dot1 {
    animation: pulse 1.5s infinite;
}

.dot2 {
    animation: pulse 1.5s infinite 0.3s;
}

.dot3 {
    animation: pulse 1.5s infinite 0.6s;
}

@keyframes pulse {
    0%, 100% {
        transform: scale(1);
        opacity: 0.6;
    }
    50% {
        transform: scale(1.3);
        opacity: 1;
    }
}

.bot-tabs {
    display: flex;
    gap: 2px;
    margin-bottom: -15px;
}

.tab-button {
    background-color: #313244;
    color: #a6adc8;
    border: none;
    border-radius: 8px 8px 0 0;
    padding: 8px 16px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s;
    flex: 1;
    text-align: center;
}

.tab-button:hover {
    background-color: #45475a;
    color: #cdd6f4;
}

.tab-button.active {
    background-color: #45475a;
    color: #cdd6f4;
}

.bot-tabs-content {
    background-color: #45475a;
    border-radius: 0 8px 8px 8px;
    padding: 16px;
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

.settings-section-title {
    margin-top: 0;
    margin-bottom: 12px;
    color: #89b4fa;
    font-size: 16px;
    font-weight: 500;
    text-align: center;
}

.bot-info {
    display: flex;
    justify-content: center;
    margin-bottom: 5px;
}

.depth-card {
    background-color: #313244;
    border-radius: 8px;
    padding: 12px 16px;
    text-align: center;
    width: 100%;
    border: 1px solid #45475a;
}

.depth-display {
    font-size: 16px;
    margin: 0 0 5px 0;
    font-weight: 400;
}

.depth-display strong {
    color: #89b4fa;
    font-weight: 600;
}

.key-hint {
    font-size: 12px;
    color: #a6adc8;
    margin: 0;
    font-weight: 300;
}

.bot-controls {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.control-group {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

.control-item {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.toggle-container {
    position: relative;
}

.toggle-input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
}

.toggle-label {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
}

.toggle-button {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 20px;
    background-color: #45475a;
    border-radius: 20px;
    transition: all 0.3s;
}

.toggle-button:before {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background-color: #cdd6f4;
    top: 2px;
    left: 2px;
    transition: all 0.3s;
}

.toggle-input:checked + .toggle-label .toggle-button {
    background-color: #89b4fa;
}

.toggle-input:checked + .toggle-label .toggle-button:before {
    transform: translateX(20px);
}

.toggle-text {
    font-size: 14px;
}

.slider-container {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.slider-container label {
    font-size: 13px;
    color: #a6adc8;
}

.number-input {
    width: 100%;
    background: #313244;
    border: 1px solid #45475a;
    border-radius: 6px;
    color: #cdd6f4;
    padding: 8px 10px;
    font-size: 14px;
    transition: border-color 0.3s;
}

.number-input:focus {
    outline: none;
    border-color: #89b4fa;
}

.bot-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 5px;
}

.action-button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: none;
    border-radius: 8px;
    padding: 10px 16px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
}

.primary-button {
    background-color: #89b4fa;
    color: #1e1e2e;
}

.primary-button:hover {
    background-color: #b4befe;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(137, 180, 250, 0.3);
}

.secondary-button {
    background-color: #45475a;
    color: #cdd6f4;
}

.secondary-button:hover {
    background-color: #585b70;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(69, 71, 90, 0.3);
}

.action-button:active {
    transform: translateY(0);
}

.depth-control {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.depth-control label {
    font-size: 13px;
    color: #a6adc8;
}

.slider-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}

.depth-slider {
    flex: 1;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: #45475a;
    border-radius: 3px;
    outline: none;
}

.depth-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #89b4fa;
    cursor: pointer;
}

.depth-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #89b4fa;
    cursor: pointer;
}

.depth-button {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: #45475a;
    color: #cdd6f4;
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 16px;
    font-weight: bold;
    transition: background-color 0.2s;
}

.depth-button:hover {
    background: #585b70;
}

#depthValue {
    font-size: 14px;
    font-weight: 500;
    color: #89b4fa;
    text-align: center;
}

@keyframes rotate {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}
`;
  var advancedStyles = `
.advanced-section {
    margin-top: 15px;
    padding-top: 15px;
    border-top: 1px solid #313244;
}

.profile-selection {
    margin-top: 15px;
}

.playStyle-controls, .advanced-controls {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.style-slider-container {
    display: flex;
    align-items: center;
    gap: 10px;
}

.style-slider-container label {
    font-size: 13px;
    color: #cdd6f4;
    width: 120px;
}

.style-slider {
    flex: 1;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: #313244;
    border-radius: 3px;
    outline: none;
}

.style-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #89b4fa;
    cursor: pointer;
}

.style-slider-container span {
    font-size: 14px;
    font-weight: 500;
    color: #89b4fa;
    width: 20px;
    text-align: center;
}

.highlight-color-picker {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 10px;
}

.highlight-color-picker label {
    font-size: 13px;
    color: #cdd6f4;
}

.color-input {
    -webkit-appearance: none;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 50%;
    background: none;
    cursor: pointer;
}

.color-input::-webkit-color-swatch {
    border: none;
    border-radius: 50%;
    box-shadow: 0 0 0 2px #45475a;
}

.opening-selection {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 10px;
}

.opening-selection label {
    font-size: 13px;
    color: #cdd6f4;
}

.select-input {
    flex: 1;
    background: #313244;
    border: 1px solid #45475a;
    border-radius: 6px;
    color: #cdd6f4;
    padding: 8px 10px;
    font-size: 14px;
    transition: border-color 0.3s;
}

.select-input:focus {
    outline: none;
    border-color: #89b4fa;
}
`;

  // ui.js
  function setupUI(myVars, myFunctions) {
    let dynamicStyles = null;
    function addAnimation(body) {
      if (!dynamicStyles) {
        dynamicStyles = document.createElement("style");
        dynamicStyles.type = "text/css";
        document.head.appendChild(dynamicStyles);
      }
      dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
    }
    myFunctions.spinner = function() {
      if (window.isThinking == true) {
        $("#thinking-indicator").addClass("active");
      }
      if (window.isThinking == false) {
        $("#thinking-indicator").removeClass("active");
      }
    };
    myFunctions.loadEx = function() {
      try {
        window.board = $("chess-board")[0] || $("wc-chess-board")[0];
        myVars.board = window.board;
        var div = document.createElement("div");
        div.setAttribute("id", "settingsContainer");
        div.innerHTML = mainTemplate;
        div.prepend($(spinnerTemplate)[0]);
        window.board.parentElement.parentElement.appendChild(div);
        var botStyles = document.createElement("style");
        botStyles.innerHTML = mainStyles + advancedStyles;
        document.head.appendChild(botStyles);
        addAnimation(`@keyframes rotate {
                0% { transform: rotate(0deg); }
                100% { transform: rotate(360deg); }
            }`);
        $("#advanced-settings .advanced-controls").append(advancedSettingsTemplate);
        myFunctions.loadSettings();
        applySettingsToUI(myVars);
        myVars.loaded = true;
      } catch (error) {
        console.log(error);
      }
    };
    function applySettingsToUI(myVars2) {
      $("#autoRun").prop("checked", myVars2.autoRun);
      $("#autoMove").prop("checked", myVars2.autoMove);
      $("#adaptToRating").prop("checked", myVars2.adaptToRating !== void 0 ? myVars2.adaptToRating : true);
      $("#useOpeningBook").prop("checked", myVars2.useOpeningBook !== void 0 ? myVars2.useOpeningBook : true);
      $("#enableHotkeys").prop("checked", myVars2.enableHotkeys !== void 0 ? myVars2.enableHotkeys : true);
      $("#randomizeTiming").prop("checked", myVars2.randomizeTiming !== void 0 ? myVars2.randomizeTiming : true);
      $("#depthSlider").val(myVars2.lastValue);
      $("#depthValue").text(myVars2.lastValue);
      $("#depthText").html("Current Depth: <strong>" + myVars2.lastValue + "</strong>");
      $("#timeDelayMin").val(GM_getValue("timeDelayMin", 0.1));
      $("#timeDelayMax").val(GM_getValue("timeDelayMax", 1));
      if (myVars2.highlightColor) {
        $("#highlightColor").val(myVars2.highlightColor);
      }
      if (myVars2.playStyle) {
        const aggressiveValue = Math.round((myVars2.playStyle.aggressive - 0.3) / 0.5 * 10);
        $("#aggressiveSlider").val(aggressiveValue);
        $("#aggressiveValue").text(aggressiveValue);
        const defensiveValue = Math.round((myVars2.playStyle.defensive - 0.3) / 0.5 * 10);
        $("#defensiveSlider").val(defensiveValue);
        $("#defensiveValue").text(defensiveValue);
        const tacticalValue = Math.round((myVars2.playStyle.tactical - 0.2) / 0.6 * 10);
        $("#tacticalSlider").val(tacticalValue);
        $("#tacticalValue").text(tacticalValue);
        const positionalValue = Math.round((myVars2.playStyle.positional - 0.2) / 0.6 * 10);
        $("#positionalSlider").val(positionalValue);
        $("#positionalValue").text(positionalValue);
      }
      if (myVars2.blunderRate !== void 0) {
        const blunderValue = Math.round(myVars2.blunderRate * 10);
        $("#blunderRateSlider").val(blunderValue);
        $("#blunderRateValue").text(blunderValue);
      }
      if (myVars2.mouseMovementRealism !== void 0) {
        const movementValue = Math.round(myVars2.mouseMovementRealism * 10);
        $("#mouseMovementSlider").val(movementValue);
        $("#mouseMovementSliderValue").text(movementValue);
      }
      if (myVars2.preferredOpenings && myVars2.preferredOpenings.length === 1) {
        $("#preferredOpeningSelect").val(myVars2.preferredOpenings[0]);
      }
      console.log("Settings applied to UI");
    }
    return myFunctions;
  }

  // events/ui-events.js
  function setupUIEventHandlers(myVars, myFunctions) {
    $(document).on("input", "#depthSlider", function() {
      const depth = parseInt($(this).val());
      $("#depthValue").text(depth);
      myVars.lastValue = depth;
      $("#depthText")[0].innerHTML = "Current Depth: <strong>" + depth + "</strong>";
      myFunctions.saveSettings();
    });
    $(document).on("click", "#decreaseDepth", function() {
      const currentDepth = parseInt($("#depthSlider").val());
      if (currentDepth > 1) {
        const newDepth = currentDepth - 1;
        $("#depthSlider").val(newDepth).trigger("input");
      }
    });
    $(document).on("click", "#increaseDepth", function() {
      const currentDepth = parseInt($("#depthSlider").val());
      if (currentDepth < 26) {
        const newDepth = currentDepth + 1;
        $("#depthSlider").val(newDepth).trigger("input");
      }
    });
    $(document).on("click", ".tab-button", function() {
      $(".tab-button").removeClass("active");
      $(this).addClass("active");
      const tabId = $(this).data("tab");
      $(".tab-content").removeClass("active");
      $(`#${tabId}`).addClass("active");
    });
  }

  // events/style-events.js
  function setupStyleEventHandlers(myVars, myFunctions) {
    $(document).on("input", ".style-slider", function() {
      const value = $(this).val();
      $(`#${this.id}Value`).text(value);
      const styleType = this.id.replace("Slider", "");
      if (styleType === "blunderRate") {
        myVars.blunderRate = parseFloat(value) / 10;
      } else if (myVars.playStyle && styleType in myVars.playStyle) {
        if (styleType === "aggressive" || styleType === "defensive") {
          myVars.playStyle[styleType] = 0.3 + parseFloat(value) / 10 * 0.5;
        } else {
          myVars.playStyle[styleType] = 0.2 + parseFloat(value) / 10 * 0.6;
        }
      }
      myFunctions.saveSettings();
    });
    $(document).on("change", "#autoRun, #autoMove, #adaptToRating, #useOpeningBook, #enableHotkeys, #randomizeTiming", function() {
      const id = $(this).attr("id");
      myVars[id] = $(this).prop("checked");
      if (id === "autoMove") {
        console.log(`Auto move set to: ${myVars.autoMove}`);
      }
      myFunctions.saveSettings();
    });
    $(document).on("input", "#highlightColor", function() {
      myVars.highlightColor = $(this).val();
      myFunctions.saveSettings();
    });
  }

  // events/advanced-events.js
  function setupAdvancedEventHandlers(myVars, myFunctions) {
    $(document).on("change", "#preferredOpeningSelect", function() {
      const selectedOpening = $(this).val();
      if (selectedOpening === "random") {
        myVars.preferredOpenings = ["e4", "d4", "c4", "Nf3"].sort(() => Math.random() - 0.5);
      } else {
        myVars.preferredOpenings = [selectedOpening];
      }
      myFunctions.saveSettings();
    });
    $(document).on("input", "#mouseMovementSlider", function() {
      const value = $(this).val();
      $("#mouseMovementSliderValue").text(value);
      myVars.mouseMovementRealism = parseFloat(value) / 10;
      myFunctions.saveSettings();
    });
    $(document).on("change", "#playingProfileSelect", function() {
      const profile = $(this).val();
      if (profile !== "custom") {
        switch (profile) {
          case "beginner":
            $("#depthSlider").val(3).trigger("input");
            $("#blunderRateSlider").val(7).trigger("input");
            $("#aggressiveSlider").val(Math.floor(3 + Math.random() * 5)).trigger("input");
            $("#tacticalSlider").val(3).trigger("input");
            break;
          case "intermediate":
            $("#depthSlider").val(6).trigger("input");
            $("#blunderRateSlider").val(5).trigger("input");
            $("#tacticalSlider").val(5).trigger("input");
            break;
          case "advanced":
            $("#depthSlider").val(9).trigger("input");
            $("#blunderRateSlider").val(3).trigger("input");
            $("#tacticalSlider").val(7).trigger("input");
            break;
          case "expert":
            $("#depthSlider").val(12).trigger("input");
            $("#blunderRateSlider").val(2).trigger("input");
            $("#tacticalSlider").val(8).trigger("input");
            $("#positionalSlider").val(8).trigger("input");
            break;
          case "master":
            $("#depthSlider").val(15).trigger("input");
            $("#blunderRateSlider").val(1).trigger("input");
            $("#tacticalSlider").val(9).trigger("input");
            $("#positionalSlider").val(9).trigger("input");
            break;
        }
        setTimeout(myFunctions.saveSettings, 100);
      }
    });
    $(document).on("change", "#timeDelayMin, #timeDelayMax", function() {
      myFunctions.saveSettings();
    });
  }

  // events.js
  function setupEventHandlers(myVars, myFunctions, engine) {
    document.onkeydown = function(e) {
      if (!myVars.enableHotkeys) return;
      switch (e.keyCode) {
        case 81:
          myFunctions.runChessEngine(1);
          break;
        case 87:
          myFunctions.runChessEngine(2);
          break;
        case 69:
          myFunctions.runChessEngine(3);
          break;
        case 82:
          myFunctions.runChessEngine(4);
          break;
        case 84:
          myFunctions.runChessEngine(5);
          break;
        case 89:
          myFunctions.runChessEngine(6);
          break;
        case 85:
          myFunctions.runChessEngine(7);
          break;
        case 73:
          myFunctions.runChessEngine(8);
          break;
        case 79:
          myFunctions.runChessEngine(9);
          break;
        case 80:
          myFunctions.runChessEngine(10);
          break;
        case 65:
          myFunctions.runChessEngine(11);
          break;
        case 83:
          myFunctions.runChessEngine(12);
          break;
        case 68:
          myFunctions.runChessEngine(13);
          break;
        case 70:
          myFunctions.runChessEngine(14);
          break;
        case 71:
          myFunctions.runChessEngine(15);
          break;
        case 72:
          myFunctions.runChessEngine(16);
          break;
        case 74:
          myFunctions.runChessEngine(17);
          break;
        case 75:
          myFunctions.runChessEngine(18);
          break;
        case 76:
          myFunctions.runChessEngine(19);
          break;
        case 90:
          myFunctions.runChessEngine(20);
          break;
        case 88:
          myFunctions.runChessEngine(21);
          break;
        case 67:
          myFunctions.runChessEngine(22);
          break;
        case 86:
          myFunctions.runChessEngine(23);
          break;
        case 66:
          myFunctions.runChessEngine(24);
          break;
        case 78:
          myFunctions.runChessEngine(25);
          break;
        case 77:
          myFunctions.runChessEngine(26);
          break;
        case 187:
          myFunctions.runChessEngine(100);
          break;
      }
    };
    $(document).ready(function() {
      setupUIEventHandlers(myVars, myFunctions);
      setupStyleEventHandlers(myVars, myFunctions);
      setupAdvancedEventHandlers(myVars, myFunctions);
    });
  }

  // parser.js
  function setupParser(myVars, myFunctions) {
    myFunctions.parser = function(e) {
      if (e.data.includes("bestmove")) {
        const bestMove = e.data.split(" ")[1];
        let alternativeMoves = [bestMove];
        try {
          if (e.data.includes("pv")) {
            const lines = e.data.split("\n").filter((line) => line.includes(" pv ")).map((line) => {
              const pvIndex = line.indexOf(" pv ");
              return line.substring(pvIndex + 4).split(" ")[0];
            });
            if (lines.length > 1) {
              alternativeMoves = lines;
            }
          }
        } catch (error) {
          console.log("Error extracting alternative moves", error);
        }
        let moveToPlay = bestMove;
        const currentDepth = myVars.lastValue;
        if (currentDepth >= 15 && alternativeMoves.length > 1 && Math.random() < 0.35) {
          const maxIndex = Math.min(5, alternativeMoves.length);
          const randomIndex = Math.floor(Math.random() * (maxIndex - 1)) + 1;
          moveToPlay = alternativeMoves[randomIndex] || bestMove;
          console.log(`Using alternative move ${moveToPlay} instead of best move ${bestMove}`);
        } else if (Math.random() < myFunctions.getBlunderProbability()) {
          moveToPlay = myFunctions.generateHumanLikeMove(bestMove, e.data);
          console.log(`Using human-like move ${moveToPlay} instead of best move ${bestMove}`);
        }
        myFunctions.color(moveToPlay);
        window.isThinking = false;
      }
    };
    myFunctions.getBlunderProbability = function() {
      const userBlunderRate = myVars.blunderRate !== void 0 ? myVars.blunderRate : 0.05;
      const gamePhase = myFunctions.estimateGamePhase();
      const timeRemaining = myFunctions.estimateTimeRemaining();
      const complexity = myFunctions.estimatePositionComplexity();
      let baseProb = userBlunderRate;
      if (timeRemaining < 30) {
        baseProb += 0.1 * (1 - timeRemaining / 30);
      }
      if (complexity > 0.6) {
        baseProb += 0.05 * (complexity - 0.6) * 2;
      }
      if (gamePhase > 30) {
        baseProb += 0.03 * ((gamePhase - 30) / 10);
      }
      return Math.min(0.4, baseProb * (0.7 + Math.random() * 0.6));
    };
    myFunctions.generateHumanLikeMove = function(bestMove, engineData) {
      if (engineData.includes("pv") && Math.random() < 0.4) {
        try {
          const lines = engineData.split("\n").filter((line) => line.includes(" pv ")).map((line) => {
            const pvIndex = line.indexOf(" pv ");
            return line.substring(pvIndex + 4).split(" ")[0];
          });
          if (lines.length > 1) {
            const moveIndex = Math.floor(Math.pow(Math.random(), 2.5) * Math.min(lines.length, 4));
            return lines[moveIndex] || bestMove;
          }
        } catch (e) {
          console.log("Error extracting alternative moves", e);
        }
      }
      if (Math.random() < 0.15) {
        const fromSquare = bestMove.substring(0, 2);
        const toSquare = bestMove.substring(2, 4);
        if (Math.random() < 0.7) {
          const files = "abcdefgh";
          const ranks = "12345678";
          const fromFile = fromSquare.charAt(0);
          const fromRank = fromSquare.charAt(1);
          const toFile = toSquare.charAt(0);
          const toRank = toSquare.charAt(1);
          const fileDiff = files.indexOf(toFile) - files.indexOf(fromFile);
          const rankDiff = ranks.indexOf(toRank) - ranks.indexOf(fromRank);
          if (Math.abs(fileDiff) > 1 || Math.abs(rankDiff) > 1) {
            const newToFile = files[files.indexOf(fromFile) + (fileDiff > 0 ? Math.max(1, fileDiff - 1) : Math.min(-1, fileDiff + 1))];
            const newToRank = ranks[ranks.indexOf(fromRank) + (rankDiff > 0 ? Math.max(1, rankDiff - 1) : Math.min(-1, rankDiff + 1))];
            if (newToFile && newToRank) {
              const alternativeMove = fromSquare + newToFile + newToRank;
              for (let each = 0; each < window.board.game.getLegalMoves().length; each++) {
                if (window.board.game.getLegalMoves()[each].from === fromSquare && window.board.game.getLegalMoves()[each].to === newToFile + newToRank) {
                  return alternativeMove;
                }
              }
            }
          }
        }
      }
      return bestMove;
    };
  }

  // utilities.js
  function setupUtilities(myVars) {
    const myFunctions = {};
    let stop_b = stop_w = 0;
    let s_br = s_br2 = s_wr = s_wr2 = 0;
    let obs = "";
    setupParser(myVars, myFunctions);
    myFunctions.rescan = function(lev) {
      var ari = $("chess-board").find(".piece").map(function() {
        return this.className;
      }).get();
      jack = ari.map((f) => f.substring(f.indexOf(" ") + 1));
      function removeWord(arr, word) {
        for (var i2 = 0; i2 < arr.length; i2++) {
          arr[i2] = arr[i2].replace(word, "");
        }
      }
      removeWord(ari, "square-");
      jack = ari.map((f) => f.substring(f.indexOf(" ") + 1));
      for (var i = 0; i < jack.length; i++) {
        jack[i] = jack[i].replace("br", "r").replace("bn", "n").replace("bb", "b").replace("bq", "q").replace("bk", "k").replace("bb", "b").replace("bn", "n").replace("br", "r").replace("bp", "p").replace("wp", "P").replace("wr", "R").replace("wn", "N").replace("wb", "B").replace("br", "R").replace("wn", "N").replace("wb", "B").replace("wq", "Q").replace("wk", "K").replace("wb", "B");
      }
      str2 = "";
      var count = 0, str = "";
      for (var j = 8; j > 0; j--) {
        for (var i = 1; i < 9; i++) {
          (str = jack.find((el) => el.includes([i] + [j]))) ? str = str.replace(/[^a-zA-Z]+/g, "") : str = "";
          if (str == "") {
            count++;
            str = count.toString();
            if (!isNaN(str2.charAt(str2.length - 1))) str2 = str2.slice(0, -1);
            else {
              count = 1;
              str = count.toString();
            }
          }
          str2 += str;
          if (i == 8) {
            count = 0;
            str2 += "/";
          }
        }
      }
      str2 = str2.slice(0, -1);
      color = "";
      wk = wq = bk = bq = "0";
      const move = $("vertical-move-list").children();
      if (move.length < 2) {
        stop_b = stop_w = s_br = s_br2 = s_wr = s_wr2 = 0;
      }
      if (stop_b != 1) {
        if (move.find(".black.node:contains('K')").length) {
          bk = "";
          bq = "";
          stop_b = 1;
          console.log("debug secb");
        }
      } else {
        bq = "";
        bk = "";
      }
      if (stop_b != 1) (bk = move.find(".black.node:contains('O-O'):not(:contains('O-O-O'))").length ? "" : "k") ? bq = move.find(".black.node:contains('O-O-O')").length ? bk = "" : "q" : bq = "";
      if (s_br != 1) {
        if (move.find(".black.node:contains('R')").text().match("[abcd]+")) {
          bq = "";
          s_br = 1;
        }
      } else bq = "";
      if (s_br2 != 1) {
        if (move.find(".black.node:contains('R')").text().match("[hgf]+")) {
          bk = "";
          s_br2 = 1;
        }
      } else bk = "";
      if (stop_b == 0) {
        if (s_br == 0) {
          if (move.find(".white.node:contains('xa8')").length > 0) {
            bq = "";
            s_br = 1;
            console.log("debug b castle_r");
          }
        }
        if (s_br2 == 0) {
          if (move.find(".white.node:contains('xh8')").length > 0) {
            bk = "";
            s_br2 = 1;
            console.log("debug b castle_l");
          }
        }
      }
      if (stop_w != 1) {
        if (move.find(".white.node:contains('K')").length) {
          wk = "";
          wq = "";
          stop_w = 1;
          console.log("debug secw");
        }
      } else {
        wq = "";
        wk = "";
      }
      if (stop_w != 1) (wk = move.find(".white.node:contains('O-O'):not(:contains('O-O-O'))").length ? "" : "K") ? wq = move.find(".white.node:contains('O-O-O')").length ? wk = "" : "Q" : wq = "";
      if (s_wr != 1) {
        if (move.find(".white.node:contains('R')").text().match("[abcd]+")) {
          wq = "";
          s_wr = 1;
        }
      } else wq = "";
      if (s_wr2 != 1) {
        if (move.find(".white.node:contains('R')").text().match("[hgf]+")) {
          wk = "";
          s_wr2 = 1;
        }
      } else wk = "";
      if (stop_w == 0) {
        if (s_wr == 0) {
          if (move.find(".black.node:contains('xa1')").length > 0) {
            wq = "";
            s_wr = 1;
            console.log("debug w castle_l");
          }
        }
        if (s_wr2 == 0) {
          if (move.find(".black.node:contains('xh1')").length > 0) {
            wk = "";
            s_wr2 = 1;
            console.log("debug w castle_r");
          }
        }
      }
      if ($(".coordinates").children().first().text() == 1) {
        str2 = str2 + " b " + wk + wq + bk + bq;
        color = "white";
      } else {
        str2 = str2 + " w " + wk + wq + bk + bq;
        color = "black";
      }
      return str2;
    };
    myFunctions.color = function(dat) {
      response = dat;
      var res1 = response.substring(0, 2);
      var res2 = response.substring(2, 4);
      if (myVars.autoMove === true) {
        console.log(`Auto move enabled, moving from ${res1} to ${res2}`);
        myFunctions.movePiece(res1, res2);
      } else {
        console.log(`Auto move disabled, highlighting ${res1} to ${res2}`);
      }
      window.isThinking = false;
      res1 = res1.replace(/^a/, "1").replace(/^b/, "2").replace(/^c/, "3").replace(/^d/, "4").replace(/^e/, "5").replace(/^f/, "6").replace(/^g/, "7").replace(/^h/, "8");
      res2 = res2.replace(/^a/, "1").replace(/^b/, "2").replace(/^c/, "3").replace(/^d/, "4").replace(/^e/, "5").replace(/^f/, "6").replace(/^g/, "7").replace(/^h/, "8");
      const highlightColor = myVars.highlightColor || "rgb(235, 97, 80)";
      $(window.board.nodeName).prepend(`<div class="highlight square-${res2} bro" style="background-color: ${highlightColor}; opacity: 0.71;" data-test-element="highlight"></div>`).children(":first").delay(1800).queue(function() {
        $(this).remove();
      });
      $(window.board.nodeName).prepend(`<div class="highlight square-${res1} bro" style="background-color: ${highlightColor}; opacity: 0.71;" data-test-element="highlight"></div>`).children(":first").delay(1800).queue(function() {
        $(this).remove();
      });
    };
    myFunctions.movePiece = function(from, to) {
      let isLegalMove = false;
      let moveObject = null;
      for (let each = 0; each < window.board.game.getLegalMoves().length; each++) {
        if (window.board.game.getLegalMoves()[each].from === from && window.board.game.getLegalMoves()[each].to === to) {
          isLegalMove = true;
          moveObject = window.board.game.getLegalMoves()[each];
          break;
        }
      }
      if (!isLegalMove) {
        console.log(`Attempted illegal move: ${from} to ${to}`);
        return;
      }
      setTimeout(() => {
        try {
          window.board.game.move({
            ...moveObject,
            promotion: moveObject.promotion || "q",
            // Default to queen for simplicity
            animate: true,
            userGenerated: true
          });
          console.log(`Successfully moved from ${from} to ${to}`);
        } catch (error) {
          console.error("Error making move:", error);
        }
      }, 100 + Math.random() * 300);
    };
    myFunctions.other = function(delay) {
      const gamePhase = myFunctions.estimateGamePhase();
      const positionComplexity = myFunctions.estimatePositionComplexity();
      let naturalDelay = delay;
      if (gamePhase < 10) {
        naturalDelay *= 0.6 + Math.random() * 0.4;
      }
      if (positionComplexity > 0.7) {
        naturalDelay *= 1 + Math.random() * 1.5;
      }
      naturalDelay *= 0.85 + Math.random() * 0.3;
      var endTime = Date.now() + naturalDelay;
      var timer = setInterval(() => {
        if (Date.now() >= endTime) {
          myFunctions.autoRun(myFunctions.getAdjustedDepth());
          window.canGo = true;
          clearInterval(timer);
        }
      }, 10);
    };
    myFunctions.getAdjustedDepth = function() {
      const timeRemaining = myFunctions.estimateTimeRemaining();
      const gamePhase = myFunctions.estimateGamePhase();
      const positionType = myFunctions.analyzePositionType(window.board.game.getFEN());
      const isPositionCritical = myFunctions.isPositionCriticalNow();
      let baseDepth = myVars.lastValue;
      if (timeRemaining < 10) {
        return Math.floor(Math.random() * 3) + 1;
      } else if (timeRemaining < 30) {
        return Math.floor(Math.random() * 4) + 4;
      } else if (timeRemaining < 60) {
        return Math.floor(Math.random() * 7) + 6;
      } else if (timeRemaining < 120) {
        return Math.floor(Math.random() * 7) + 9;
      } else {
        if (!isPositionCritical && Math.random() < 0.07) {
          return Math.floor(Math.random() * 4) + 2;
        }
        return Math.floor(Math.random() * 9) + 11;
      }
    };
    myFunctions.analyzePositionType = function(fen) {
      const piecesCount = fen.split(" ")[0].match(/[pnbrqkPNBRQK]/g).length;
      if (piecesCount > 25) return "opening";
      if (piecesCount < 12) return "endgame";
      return "middlegame";
    };
    myFunctions.isPositionCriticalNow = function() {
      try {
        const inCheck = window.board.game.inCheck();
        const fen = window.board.game.getFEN();
        const whiteMaterial = myFunctions.countMaterial(fen, true);
        const blackMaterial = myFunctions.countMaterial(fen, false);
        const materialDifference = Math.abs(whiteMaterial - blackMaterial);
        return inCheck || materialDifference < 2;
      } catch (e) {
        return false;
      }
    };
    myFunctions.countMaterial = function(fen, isWhite) {
      const position = fen.split(" ")[0];
      let material = 0;
      const pieces = isWhite ? "PNBRQK" : "pnbrqk";
      const values = {
        "P": 1,
        "N": 3,
        "B": 3,
        "R": 5,
        "Q": 9,
        "K": 0,
        "p": 1,
        "n": 3,
        "b": 3,
        "r": 5,
        "q": 9,
        "k": 0
      };
      for (let char of position) {
        if (pieces.includes(char)) {
          material += values[char];
        }
      }
      return material;
    };
    myFunctions.estimateGamePhase = function() {
      try {
        const moveList = $("vertical-move-list").children().length;
        return moveList / 2;
      } catch (e) {
        return 15;
      }
    };
    myFunctions.estimateTimeRemaining = function() {
      let remainingTime = 600;
      try {
        const clockEl = document.querySelector(".clock-component.clock-bottom");
        if (clockEl) {
          const timeText = clockEl.textContent;
          if (timeText.includes(":")) {
            const parts = timeText.split(":");
            if (parts.length === 2) {
              const minutes = parseInt(parts[0]);
              const seconds = parseInt(parts[1]);
              if (!isNaN(minutes) && !isNaN(seconds)) {
                remainingTime = minutes * 60 + seconds;
              } else {
                console.log("Error parsing time:", timeText);
              }
            }
          } else {
            const seconds = parseInt(timeText);
            if (!isNaN(seconds)) {
              remainingTime = seconds;
            } else {
              console.log("Error parsing time:", timeText);
            }
          }
        } else {
          console.log("Clock element not found with selector '.clock-component.clock-bottom'");
        }
      } catch (e) {
        console.log("Error getting time remaining:", e);
      }
      console.log("Remaining time:", remainingTime);
      return remainingTime;
    };
    myFunctions.estimatePositionComplexity = function() {
      return Math.random() * 0.8 + 0.2;
    };
    myFunctions.saveSettings = function() {
      try {
        GM_setValue("autoRun", myVars.autoRun);
        GM_setValue("autoMove", myVars.autoMove);
        GM_setValue("timeDelayMin", $("#timeDelayMin").val());
        GM_setValue("timeDelayMax", $("#timeDelayMax").val());
        GM_setValue("depthValue", myVars.lastValue);
        GM_setValue("highlightColor", myVars.highlightColor);
        GM_setValue("playStyle", myVars.playStyle);
        GM_setValue("blunderRate", myVars.blunderRate);
        GM_setValue("adaptToRating", myVars.adaptToRating);
        GM_setValue("useOpeningBook", myVars.useOpeningBook);
        GM_setValue("preferredOpenings", myVars.preferredOpenings);
        GM_setValue("enableHotkeys", myVars.enableHotkeys);
        GM_setValue("randomizeTiming", myVars.randomizeTiming);
        GM_setValue("mouseMovementRealism", myVars.mouseMovementRealism);
        console.log("Settings saved successfully");
      } catch (error) {
        console.error("Error saving settings:", error);
      }
    };
    myFunctions.loadSettings = function() {
      try {
        myVars.autoRun = GM_getValue("autoRun", false);
        myVars.autoMove = GM_getValue("autoMove", false);
        myVars.lastValue = GM_getValue("depthValue", 11);
        myVars.highlightColor = GM_getValue("highlightColor", "rgb(235, 97, 80)");
        myVars.blunderRate = GM_getValue("blunderRate", 0.05);
        myVars.adaptToRating = GM_getValue("adaptToRating", true);
        myVars.useOpeningBook = GM_getValue("useOpeningBook", true);
        myVars.preferredOpenings = GM_getValue("preferredOpenings", ["e4", "d4", "c4", "Nf3"]);
        myVars.enableHotkeys = GM_getValue("enableHotkeys", true);
        myVars.randomizeTiming = GM_getValue("randomizeTiming", true);
        myVars.mouseMovementRealism = GM_getValue("mouseMovementRealism", 0.7);
        const savedPlayStyle = GM_getValue("playStyle", null);
        if (savedPlayStyle) {
          myVars.playStyle = savedPlayStyle;
        }
        console.log("Settings loaded successfully");
      } catch (error) {
        console.error("Error loading settings:", error);
      }
    };
    return myFunctions;
  }

  // main.js
  window.isThinking = false;
  window.canGo = true;
  window.myTurn = false;
  window.board = null;
  function main() {
    const myVars = initializeVariables();
    const myFunctions = setupUtilities(myVars);
    myFunctions.loadSettings();
    const engine = setupEngine(myVars, myFunctions);
    document.engine = engine;
    document.myVars = myVars;
    document.myFunctions = myFunctions;
    setupUI(myVars, myFunctions, engine);
    setupEventHandlers(myVars, myFunctions, engine);
    console.log("Chess.com UltraX bot initialized with version:", currentVersion);
  }
  window.addEventListener("load", (event) => {
    main();
  });
  var waitForChessBoard = setInterval(() => {
    if (!document.myVars || !document.myFunctions) return;
    const myVars = document.myVars;
    const myFunctions = document.myFunctions;
    if (myVars.loaded) {
      window.board = $("chess-board")[0] || $("wc-chess-board")[0];
      myVars.autoRun = $("#autoRun")[0].checked;
      myVars.autoMove = $("#autoMove")[0].checked;
      let minDel = parseFloat($("#timeDelayMin")[0].value);
      let maxDel = parseFloat($("#timeDelayMax")[0].value);
      myVars.delay = Math.random() * (maxDel - minDel) + minDel;
      myVars.isThinking = window.isThinking;
      myFunctions.spinner();
      if (window.board.game.getTurn() == window.board.game.getPlayingAs()) {
        window.myTurn = true;
      } else {
        window.myTurn = false;
      }
      $("#depthText")[0].innerHTML = "Current Depth: <strong>" + myVars.lastValue + "</strong>";
    } else {
      myFunctions.loadEx();
    }
    if (!document.engine.engine) {
      myFunctions.loadChessEngine();
    }
    if (myVars.autoRun == true && window.canGo == true && window.isThinking == false && window.myTurn) {
      window.canGo = false;
      var currentDelay = myVars.delay != void 0 ? myVars.delay * 1e3 : 10;
      myFunctions.other(currentDelay);
    }
  }, 100);
})();