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