From 35c66a30f49f09b9d4b13f109bf937499791bf15 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 15:40:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Killer=20move=20=E8=A1=A8=20=E2=80=94?= =?UTF-8?q?=202-slot/depth=20+=203=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/ai/killer.rs | 72 +++++++++++++++++++++++++++++++++++++++++++ core/src/ai/mod.rs | 1 + 2 files changed, 73 insertions(+) create mode 100644 core/src/ai/killer.rs diff --git a/core/src/ai/killer.rs b/core/src/ai/killer.rs new file mode 100644 index 0000000..d8afe6e --- /dev/null +++ b/core/src/ai/killer.rs @@ -0,0 +1,72 @@ +use crate::types::Position; + +const MAX_DEPTH: usize = 32; +const SLOTS_PER_DEPTH: usize = 2; + +pub struct KillerTable { + moves: [[Option; SLOTS_PER_DEPTH]; MAX_DEPTH], +} + +impl KillerTable { + pub fn new() -> Self { + Self { + moves: [[None; SLOTS_PER_DEPTH]; MAX_DEPTH], + } + } + + /// 记录产生剪枝的走法,同一位置不会重复存储 + pub fn record(&mut self, depth: usize, pos: Position) { + if depth >= MAX_DEPTH { + return; + } + let slot0 = self.moves[depth][0]; + if slot0 != Some(pos) { + self.moves[depth][1] = slot0; + self.moves[depth][0] = Some(pos); + } + } + + /// 获取该深度的 killer moves(优先级: slot0 > slot1) + pub fn get(&self, depth: usize) -> [Option; SLOTS_PER_DEPTH] { + if depth >= MAX_DEPTH { + return [None, None]; + } + self.moves[depth] + } + + pub fn clear(&mut self) { + self.moves = [[None; SLOTS_PER_DEPTH]; MAX_DEPTH]; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_record_and_get() { + let mut kt = KillerTable::new(); + kt.record(3, Position::new(7, 7)); + assert_eq!(kt.get(3)[0], Some(Position::new(7, 7))); + } + + #[test] + fn test_two_slots_eviction() { + let mut kt = KillerTable::new(); + kt.record(1, Position::new(7, 7)); + kt.record(1, Position::new(8, 8)); + kt.record(1, Position::new(9, 9)); + let got = kt.get(1); + assert_eq!(got[0], Some(Position::new(9, 9))); + assert_eq!(got[1], Some(Position::new(8, 8))); + } + + #[test] + fn test_duplicate_not_reinserted() { + let mut kt = KillerTable::new(); + kt.record(2, Position::new(7, 7)); + kt.record(2, Position::new(7, 7)); + assert_eq!(kt.get(2)[0], Some(Position::new(7, 7))); + assert_eq!(kt.get(2)[1], None); + } +} diff --git a/core/src/ai/mod.rs b/core/src/ai/mod.rs index 211a535..c86f377 100644 --- a/core/src/ai/mod.rs +++ b/core/src/ai/mod.rs @@ -8,4 +8,5 @@ pub trait AiEngine: Send + Sync { } pub mod evaluate; +pub mod killer; pub mod search;