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


import time
import keyboard
from analysis import ChessAnalyzer
import crop


class ChessLogic:
    def __init__(self):
        self.analyzer = ChessAnalyzer()
        
        # Внутреннее состояние доски 8x8 в формате FEN символов ('P', 'n', ''...)
        self.board_state = []
        
        # Матрица булевых значений (True/False) от crop.py для сравнения изменений
        self.last_crop_matrix = None
        
        self.is_analyzed = False
        self.active_color = 'w'  # 'w' - белые, 'b' - черные

    def convert_coords_to_notation(self, row, col):
        """Переводит индексы (0..7, 0..7) в шахматную нотацию (a8...h1)"""
        files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
        ranks = ['8', '7', '6', '5', '4', '3', '2', '1']
        return f"{files[col]}{ranks[row]}"

    def start_initial_analysis(self):
        """Запускается ЕДИНОЖДЫ при нажатии клавиши 'S'"""
        print("\n[!] Нажата 'S'. Первичный анализ фигур через analysis.py...")
        
        # 1. Получаем расстановку фигур от analysis.py
        self.board_state = self.analyzer.analyze_initial_board()
        
        if self.board_state:
            # 2. Фиксируем начальную матрицу занятости клеток от crop.py
            crop_matrix, _ = crop.find_chessboard_strictly_1to1()
            self.last_crop_matrix = crop_matrix
            
            self.is_analyzed = True
            print("[✓] Начальная позиция успешно зафиксирована!")
            self.print_board()
            print(f"Начальный FEN: {self.get_fen_string()}")
            print("\n[*] Переход в режим авто-отслеживания ходов через crop.py...\n")
        else:
            print("[!] Ошибка: не удалось проанализировать доску.")

    def get_fen_string(self):
        """Генерация строки FEN из текущего состояния памяти"""
        if not self.board_state:
            return ""

        fen_rows = []
        for row in self.board_state:
            empty_count = 0
            row_fen = ""
            for cell in row:
                if cell == "":
                    empty_count += 1
                else:
                    if empty_count > 0:
                        row_fen += str(empty_count)
                        empty_count = 0
                    row_fen += cell
            if empty_count > 0:
                row_fen += str(empty_count)
            fen_rows.append(row_fen)

        position_fen = "/".join(fen_rows)
        return f"{position_fen} {self.active_color} KQkq - 0 1"

    def print_board(self):
        """Красивый вывод доски в консоль"""
        if not self.board_state:
            return
        
        print("\n    a   b   c   d   e   f   g   h")
        print("  +-------------------------------+")
        for i, row in enumerate(self.board_state):
            rank = 8 - i
            row_str = " | ".join([p if p != "" else "." for p in row])
            print(f"{rank} | {row_str} | {rank}")
            print("  +-------------------------------+")
        print("    a   b   c   d   e   f   g   h\n")

    def track_board_changes(self):
        """
        Постоянный быстрой опрос от crop.py.
        Сравнивает текущие True/False с предыдущими и определяет ход.
        """
        if not self.is_analyzed or self.last_crop_matrix is None:
            return

        # Берем свежий статус занятости клеток от crop.py (работает быстро)
        new_crop_matrix, _ = crop.find_chessboard_strictly_1to1()

        if new_crop_matrix is None:
            return

        from_cells = []  # Клетки, где фигура пропала (True -> False)
        to_cells = []    # Клетки, где фигура появилась (False -> True)

        for r in range(8):
            for c in range(8):
                old_val = self.last_crop_matrix[r][c]
                new_val = new_crop_matrix[r][c]

                if old_val and not new_val:
                    from_cells.append((r, c))
                elif not old_val and new_val:
                    to_cells.append((r, c))

        # Ход считается завершенным, когда одна клетка освободилась и одна занялась
        if len(from_cells) == 1 and len(to_cells) == 1:
            from_row, from_col = from_cells[0]
            to_row, to_col = to_cells[0]

            moved_piece = self.board_state[from_row][from_col]

            if moved_piece != "":
                from_not = self.convert_coords_to_notation(from_row, from_col)
                to_not = self.convert_coords_to_notation(to_row, to_col)

                print(f"[⚡ CHESS MOVE]: {moved_piece} c {from_not} на {to_not}")

                # Передвигаем фигуру в памяти logic.py
                self.board_state[to_row][to_col] = moved_piece
                self.board_state[from_row][from_col] = ""

                # Меняем цвет очередности хода
                self.active_color = 'b' if self.active_color == 'w' else 'w'

                # Запоминаем новое состояние от crop
                self.last_crop_matrix = new_crop_matrix

                # Выводим обновившуюся доску и FEN
                self.print_board()
                print(f"Новый FEN: {self.get_fen_string()}\n")

        # Если сменилась позиция при взятии (например, True -> True) или при рокировке,
        # просто обновляем снимок матрицы, когда доска успокоится
        elif len(from_cells) == 0 and len(to_cells) == 0:
            pass

    def run(self):
        """Главный цикл бота"""
        print("=========================================")
        print(" Шахматный бот запущен.")
        print(" Нажмите 'S' для первоначального анализа.")
        print("=========================================")

        # Горячая клавиша для запуска анализа
        keyboard.add_hotkey('s', self.start_initial_analysis)

        try:
            while True:
                # Если анализ уже был — регулярно проверяем изменения через crop
                if self.is_analyzed:
                    self.track_board_changes()
                
                # Небольшая пауза между проверками (чтобы не перегружать ЦП)
                time.sleep(0.15)

        except KeyboardInterrupt:
            print("\nПрограмма завершена.")


if __name__ == '__main__':
    logic = ChessLogic()
    logic.run()