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


else:
                chosen_tuple = random.choice(valid_candidates)
                chosen_move, chosen_score, pv_num = chosen_tuple
                choice_info = f"Случайный из {len(valid_candidates)} кандидатов (Выбран PV{pv_num})"

            is_castling = board.is_castling(chosen_move)
            san_move = board.san(chosen_move)
            best_move_uci = chosen_move.uci()

            print(f" [ВАШ ХОД]: {san_move} (UCI: {best_move_uci}) | {choice_info}")
            if is_castling:
                print(" [INFO] Рекомендуемый ход - РОКИРОВКА!")

            # --- ОБНОВЛЯЕМ ПОДСВЕТКУ В ОВЕРЛЕЕ ---
            src_sq = best_move_uci[:2]
            dst_sq = best_move_uci[2:4]
            src_box = self.get_square_rect(src_sq)
            dst_box = self.get_square_rect(dst_sq)

            if src_box and dst_box:
                self.overlay.update_move(src_box, dst_box)

            if self.mover and self.mover.auto_move_enabled:
                self.mover.execute_move(best_move_uci, self.my_color)

            return best_move_uci

        except Exception as e:
            print(f"[!] Ошибка Stockfish: {e}")
            return None

    def evaluate_current_turn(self):
        current_fen = self.get_fen_string()
        if not current_fen:
            return

        print(f"\nТекущий FEN: {current_fen}")
        if self.active_color == self.my_color:
            print(" Твой ход! Анализируем позицию через Stockfish...")
            self.analyze_with_engine(current_fen)
        else:
            print(" Сейчас ход противника. Ожидаем ответа на доске...\n")

    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):
        if hasattr(self, 'mover') and self.mover.is_moving:
            return

        board_img = crop.get_board_image() if hasattr(crop, 'get_board_image') else crop.find_chessboard_strictly_1to1()[1]
        if board_img is None:
            return

        raw_board_state = self.analyzer.get_board_state(board_img)
        if not raw_board_state:
            return

        if raw_board_state != self.board_state:
            is_legal, detected_move = self.is_legal_board_transition(raw_board_state)

            if is_legal:
                print(f"[CHANGE DETECTED]: Зафиксирован легальный ход -> {detected_move.uci()}")
                current_fen = self.get_fen_string()
                board_obj = chess.Board(current_fen) if current_fen else chess.Board()

                self.update_castling_rights(detected_move)
                self.update_en_passant_target(detected_move, board_obj)

                self.board_state = raw_board_state
                self.active_color = 'b' if self.active_color == 'w' else 'w'
                
                self.stuck_frame_count = 0
                self.last_raw_board = None

                self.print_board()
                self.evaluate_current_turn()
            else:
                if raw_board_state == self.last_raw_board:
                    self.stuck_frame_count += 1
                else:
                    self.last_raw_board = raw_board_state
                    self.stuck_frame_count = 1

                if self.stuck_frame_count >= 5:
                    print("\n[!] [AUTO-RESYNC]: Сброс позиции и авто-синхронизация...")
                    self.board_state = raw_board_state
                    self.stuck_frame_count = 0
                    self.last_raw_board = None
                    self.active_color = 'b' if self.active_color == 'w' else 'w'

                    self.print_board()
                    self.evaluate_current_turn()
                else:
                    print(f"[FRAME SKIPPED]: Изменение не по правилам ({self.stuck_frame_count}/5)...")

        time.sleep(0.2)

    def run(self):
        print("==================================================")
        print(" Шахматный бот запущен")
        print(" Нажмите 'S' - Старт анализа.")
        print(" Нажмите 'V' - Вкл/Выкл оверлей подсветок (Зелёная/Красная рамка).")
        print(" Нажмите 'C' - Принудительный выбор цвета и ориентации.")
        print(" Нажмите 'T' - Переключить чей сейчас ход (Белые/Чёрные).")
        print(" Нажмите 'M' - Смена режима сложности (Easy/Medium/Hard/Max).")
        print(" Нажмите 'L' - Вкл/Выкл физического авто-хода.")
        print(" Нажмите 'H' - Режим мыши (Humanly / Click).")
        print(" Нажмите '+' / '-' - Регулировка скорости мыши.")
        print("==================================================")

        keyboard.add_hotkey('s', self.on_start_pressed)
        keyboard.add_hotkey('v', self.overlay.toggle_highlight)
        keyboard.add_hotkey('c', self.on_color_toggle_pressed)
        keyboard.add_hotkey('t', self.toggle_active_turn)
        keyboard.add_hotkey('m', self.cycle_difficulty_mode)
        
        keyboard.add_hotkey('l', self.toggle_auto_move_and_execute)
        keyboard.add_hotkey('h', self.mover.toggle_humanly_mode)
        keyboard.add_hotkey('+', self.mover.speed_up)
        keyboard.add_hotkey('-', self.mover.speed_down)

        try:
            while True:
                if self.trigger_analysis:
                    self.trigger_analysis = False
                    self.process_initial_analysis()

                if self.trigger_toggle_color:
                    self.trigger_toggle_color = False
                    self.toggle_my_color()

                if self.is_analyzed:
                    self.track_board_changes()

                time.sleep(0.05)
        except KeyboardInterrupt:
            print("\nЗавершение программы...")
        finally:
            self.close()


if __name__ == '__main__':
    logic = ChessLogic(engine_path="stockfish.exe", mode="medium")
    logic.run()