🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

Greasy Fork is available in English.

Chess.com Real-Time AI Analysis with Player Color Indicator

실시간으로 FEN을 업로드하고 AI 분석을 받아오며, 마지막 수와 총 수(전체 수), 그리고 탭 플레이어의 색상을 표시하고 업데이트 시 무지개 색 표시기를 변경합니다.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

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

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

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

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         Chess.com Real-Time AI Analysis with Player Color Indicator
// @namespace    http://tampermonkey.net/
// @version      2.9
// @description  실시간으로 FEN을 업로드하고 AI 분석을 받아오며, 마지막 수와 총 수(전체 수), 그리고 탭 플레이어의 색상을 표시하고 업데이트 시 무지개 색 표시기를 변경합니다.
// @author       You
// @match        *://www.chess.com/play/computer*
// @grant        GM_xmlhttpRequest
// @connect      lichess.org
// ==/UserScript==

(function() {
    'use strict';

    const rainbowColors = ['#FF0000','#FF7F00','#FFFF00','#00FF00','#0000FF','#4B0082','#8F00FF'];
    let colorIndex = 0;
    let lastFen = '';
    let lastFullMoveCount = 0;
    let lastOutput = '';

    // UI 요소 생성
    const infoBox = document.createElement('div');
    Object.assign(infoBox.style, {
        position: 'fixed', top: '10px', right: '10px',
        padding: '8px 12px', background: 'rgba(0,0,0,0.7)', color: '#fff',
        fontFamily: 'monospace', fontSize: '14px', zIndex: 9999,
        borderRadius: '4px', whiteSpace: 'pre'
    });
    const textNode = document.createTextNode('분석 대기 중...');
    const indicator = document.createElement('div');
    Object.assign(indicator.style, {
        width: '12px', height: '12px', marginTop: '6px', borderRadius: '50%',
        backgroundColor: rainbowColors[0]
    });
    infoBox.append(textNode, document.createElement('br'), indicator);
    document.body.append(infoBox);

    // 보드 말 배치에서 FEN 위치 필드만 추출
    function extractPosition() {
        const board = Array.from({ length: 8 }, () => Array(8).fill(''));
        document.querySelectorAll('.piece').forEach(el => {
            const cls = el.className;
            const sqMatch = cls.match(/square-(\d\d)/);
            if (!sqMatch) return;
            const sq = sqMatch[1];
            const file = parseInt(sq.charAt(0), 10) - 1;
            const rank = parseInt(sq.charAt(1), 10) - 1;
            if (isNaN(file) || isNaN(rank)) return;
            const pCharMatch = cls.match(/piece [wb]([prnbqk])/);
            if (!pCharMatch) return;
            const map = { p:'p', r:'r', n:'n', b:'b', q:'q', k:'k' };
            let p = map[pCharMatch[1]];
            if (cls.includes(' wp ')) p = p.toUpperCase();
            board[7 - rank][file] = p;
        });
        return board.map(row => {
            let empty = 0, str = '';
            row.forEach(cell => {
                if (!cell) empty++; else { if (empty) { str += empty; empty = 0; } str += cell; }
            });
            return str + (empty ? empty : '');
        }).join('/');
    }

    // 수 정보(전체 수, half moves, 마지막 수) 가져오기
    function getMovesInfo() {
        const rows = document.querySelectorAll('.main-line-row.move-list-row');
        let fullCount = 0;
        if (rows.length) {
            fullCount = parseInt(rows[rows.length - 1].getAttribute('data-whole-move-number'), 10) || 0;
        }
        const ply = document.querySelectorAll('.node.main-line-ply');
        const halfCount = ply.length;
        const lastMove = halfCount ? ply[halfCount - 1].textContent.trim() : '';
        return { fullCount, halfCount, lastMove };
    }

    // 전체 FEN 생성
    function makeFEN(pos, turn) {
        return `${pos} ${turn} KQkq - 0 1`;
    }

    // indicator 색상 순환
    function rotateIndicator() {
        colorIndex = (colorIndex + 1) % rainbowColors.length;
        indicator.style.backgroundColor = rainbowColors[colorIndex];
    }

    // AI 분석 요청 및 화면 업데이트
    function updateAnalysis(fen, myColor, lastMove, fullCount) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: 'https://lichess.org/api/cloud-eval?fen=' + encodeURIComponent(fen) + '&multiPv=1',
            headers: { 'Accept': 'application/json' },
            onload: res => {
                try {
                    const data = JSON.parse(res.responseText);
                    let out = `총 수: ${fullCount}\n내 색상: ${myColor}\n마지막 수: ${lastMove || '-'}\n`;
                    if (data.pvs && data.pvs.length > 0) {
                        const pv = data.pvs[0];
                        const cp = pv.cp, mate = pv.mate;
                        const move = pv.moves.split(' ')[0];
                        const human = move.slice(0,2) + '→' + move.slice(2,4);
                        const ev = mate != null ? `M${mate}` : (cp != null ? (cp/100).toFixed(2) : '?');
                        out += `평가: ${ev}\n추천: ${human}`;
                    } else {
                        out += `분석 정보 없음`;
                    }
                    if (out !== lastOutput) {
                        lastOutput = out;
                        textNode.nodeValue = out;
                        rotateIndicator();
                    }
                } catch (e) {
                    console.error('AI 분석 오류:', e);
                }
            },
            onerror: err => console.error('AI 분석 요청 실패:', err)
        });
    }

    // 메인 루프: 0.1초마다 실행
    setInterval(() => {
        rotateIndicator();
        const pos = extractPosition();
        const { fullCount, halfCount, lastMove } = getMovesInfo();

        // 탭 플레이어 색상 감지 (보드 뒤집힘 상태로 판단)
        const boardEl = document.getElementById('board-play-computer');
        const myColor = boardEl.classList.contains('flipped') ? '흑' : '백';

        const turn = (halfCount % 2 === 0) ? 'w' : 'b';
        const fen = makeFEN(pos, turn);
        if (fen !== lastFen || fullCount !== lastFullMoveCount) {
            lastFen = fen;
            lastFullMoveCount = fullCount;
            updateAnalysis(fen, myColor, lastMove, fullCount);
        }
    }, 100);
})();