Загрузка данных


import chess
import chess.engine

class ChessEngine:
    def __init__(self, engine_path="stockfish.exe", time_limit=0.1):
        self.engine_path = engine_path
        self.time_limit = time_limit
        self.engine = None
        self.enabled = False  # Отключен по умолчанию
        self._start_engine()

    def _is_engine_alive(self):
        """Проверяет, запущен и живет ли процесс движка."""
        if self.engine is None:
            return False
        # В python-chess проверка процесса выполняется через poll()
        if hasattr(self.engine, 'process') and self.engine.process is not None:
            return self.engine.process.poll() is None
        return True

    def _start_engine(self):
        """Запуск или перезапуск процесса Stockfish."""
        if self.engine:
            try:
                self.engine.quit()
            except Exception:
                pass
            self.engine = None

        try:
            self.engine = chess.engine.SimpleEngine.popen_uci(self.engine_path)
            
            options = {
                "Hash": 16,
                "Threads": 1
            }
            for key, value in options.items():
                if key in self.engine.options:
                    self.engine.configure({key: value})
                    
            print("[ОК] Движок Stockfish готов!")
        except Exception as e:
            print(f"[ПРЕДУПРЕЖДЕНИЕ] Не удалось запустить движок: {e}")
            self.engine = None

    def toggle(self):
        """Переключает активное состояние движка."""
        self.enabled = not self.enabled
        # Если включили, но движок мертв — перезапускаем
        if self.enabled and not self._is_engine_alive():
            self._start_engine()
        return self.enabled

    def analyze_fen(self, fen):
        if not self.enabled:
            return None, "Движок отключен [Жми S]"

        # Авто-перезапуск при падении процесса
        if not self._is_engine_alive():
            self._start_engine()
            if not self.engine:
                return None, "Ошибка: Stockfish не запущен"

        try:
            board = chess.Board(fen)
            
            if not board.is_valid():
                return None, "Некорректная позиция FEN"

            result = self.engine.analyse(board, chess.engine.Limit(time=self.time_limit))
            
            best_move = result.get("pv")[0] if "pv" in result and result["pv"] else None
            score = result.get("score")

            if score is not None:
                if score.is_mate():
                    eval_str = f"Мат в {score.relative.mate()}"
                else:
                    cp = score.relative.score() / 100.0
                    eval_str = f"{'+' if cp > 0 else ''}{cp:.2f}"
            else:
                eval_str = "0.00"

            return best_move.uci() if best_move else None, eval_str

        except chess.engine.EngineTerminatedError:
            print("[ОШИБКА] Stockfish аварийно завершился! Перезапуск...")
            self._start_engine()
            return None, "Перезапуск Stockfish..."
        except Exception as e:
            return None, f"Ошибка анализа: {e}"

    def close(self):
        if self.engine:
            try:
                self.engine.quit()
            except Exception:
                pass