From 063a181a6e086008f51a0f7612f3686aa15987cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sun, 31 May 2026 13:53:06 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20AI=20=E4=BD=BF=E7=94=A8=20Arc=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9C=9F=E6=AD=A3=E7=9A=84=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=89=A7=E8=A1=8C=EF=BC=8C=E4=B8=8D=E9=98=BB?= =?UTF-8?q?=E5=A1=9E=20Tauri=20=E5=91=BD=E4=BB=A4=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E6=B1=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- gui/src/commands.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/gui/src/commands.rs b/gui/src/commands.rs index 6701efe..060dedc 100644 --- a/gui/src/commands.rs +++ b/gui/src/commands.rs @@ -12,7 +12,7 @@ pub struct AppState { pub board: Mutex>, pub game_mode: Mutex, pub config: Mutex, - pub ai_engine: Mutex>>, + pub ai_engine: Mutex>>, pub current_color: Mutex, pub game_over: Mutex, } @@ -43,14 +43,14 @@ pub fn new_game(mode: GameMode, config: GameConfig, state: State) -> R // 初始化 AI (如果是人机模式) if is_vs_ai { - let ai: Box = if config.use_llm { - Box::new(LlmAi::new( + let ai: std::sync::Arc = if config.use_llm { + std::sync::Arc::new(LlmAi::new( &config.llm_endpoint, &config.llm_api_key, &config.llm_model, )) } else { - Box::new(AlphaBetaAi::new(config.ai_difficulty as usize)) + std::sync::Arc::new(AlphaBetaAi::new(config.ai_difficulty as usize)) }; *state.ai_engine.lock().map_err(|e| e.to_string())? = Some(ai); } @@ -130,21 +130,29 @@ pub fn undo(steps: u32, state: State) -> Result<(), String> { #[tauri::command] pub fn ai_move(state: State) -> Result, String> { - // 预先提取棋盘和当前颜色,释放 board/color 锁 - let (board_clone, color) = { + // 在锁内提取 board、color 和 AI Arc,克隆后立即释放所有锁 + let (board_clone, color, ai_arc) = { let board_opt = state.board.lock().map_err(|e| e.to_string())?; let board = board_opt.as_ref().ok_or("游戏未开始")?.clone(); let color = *state.current_color.lock().map_err(|e| e.to_string())?; - (board, color) + let ai_guard = state.ai_engine.lock().map_err(|e| e.to_string())?; + let ai_arc = ai_guard + .as_ref() + .ok_or("AI 未初始化")? + .clone(); + (board, color, ai_arc) }; + // 所有锁在此处已释放,避免阻塞 Tauri 命令线程池 - // 持有 ai_engine 锁同步调用 best_move(阻塞 IPC 命令,但只影响 AI 走棋) - let ai_guard = state.ai_engine.lock().map_err(|e| e.to_string())?; - let ai = ai_guard.as_ref().ok_or("AI 未初始化")?; - let result = ai.best_move(&board_clone, color); - drop(ai_guard); + let (tx, rx) = std::sync::mpsc::channel(); + std::thread::spawn(move || { + let result = ai_arc.best_move(&board_clone, color); + let _ = tx.send(result); + }); - Ok(result.map(|p| (p.x, p.y))) + rx.recv_timeout(std::time::Duration::from_secs(30)) + .map_err(|_| "AI 计算超时".to_string()) + .map(|r| r.map(|p| (p.x, p.y))) } #[tauri::command]