瀏覽代碼

Merge branch 'master' of http://git.winfor.ch/nicolas/bishop

Nicolas Winkler 2 年之前
父節點
當前提交
12b2ef097f
共有 3 個文件被更改,包括 130 次插入9 次删除
  1. 1 1
      src/game.rs
  2. 117 4
      src/movegen.rs
  3. 12 4
      src/search.rs

+ 1 - 1
src/game.rs

@@ -574,7 +574,7 @@ impl Game {
     /// TODO: improve
     /// 
     pub fn is_legal(&self, mov: Move) -> bool {
-        movegen::generate_legal_moves(&mut self.clone(), self.turn).contains(&mov)
+        movegen::generate_legal_moves(&mut self.clone(), self.turn, false).contains(&mov)
     }
 
     pub fn apply(&mut self, mov: Move) -> MoveUndo {

+ 117 - 4
src/movegen.rs

@@ -3,7 +3,9 @@ use bitboard::Square;
 use bitboard::*;
 use game::Game;
 use hash::{Cache, EntryType};
+use std::iter::Iterator;
 
+use crate::evaluate::evaluate;
 use crate::hash::CacheEntry;
 
 pub type Side = bool;
@@ -155,6 +157,112 @@ impl SimpleMove {
 }
 
 
+#[derive(PartialEq)]
+enum SortingState {
+    PvMove,
+    Captures,
+    Killers,
+    Quiets
+}
+
+///
+/// generates and sorts moves which can then be extracted via an Iterator interface
+/// 
+pub struct MoveGenerator {
+
+    game: Game,
+    moves: Vec<Move>,
+
+    captures: Vec<Move>,
+    quiets: Vec<Move>,
+
+    state: SortingState,
+
+    pv_move: Option<Move>,
+    killers: Vec<Move>
+}
+
+impl MoveGenerator {
+    pub fn generate_legal_moves(game: &mut Game, ce: Option<&CacheEntry>, killers: &[Move], side: Side) -> Self {
+        MoveGenerator {
+            game: game.clone(),
+            moves: generate_legal_moves(game, side, false),
+            captures: Vec::new(),
+            quiets: Vec::new(),
+            state: if ce.is_some() { SortingState::PvMove } else { SortingState::Captures },
+            pv_move: ce.map(|e| e.mov),
+            killers: killers.to_vec()
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        return self.moves.is_empty() && self.captures.is_empty() && self.quiets.is_empty();
+    }
+}
+
+impl Iterator for MoveGenerator {
+    type Item = Move;
+
+    fn next(&mut self) -> Option<Move> {
+        while self.state != SortingState::Quiets || !self.is_empty() {
+            match self.state {
+                SortingState::PvMove => {
+                    self.state = SortingState::Captures;
+                    if let Some(pv) = self.pv_move {
+                        if self.moves.contains(&pv) {
+                            self.moves.retain(|m| *m != pv);
+                            return Some(pv);
+                        }
+                    }
+                },
+                SortingState::Captures => {
+                    if self.captures.is_empty() {
+                        self.captures = self.moves.iter().filter(|m| m.is_capture()).map(|m| m.clone()).collect();
+                        self.quiets = self.moves.iter().filter(|m| !m.is_capture()).map(|m| m.clone()).collect();
+                        self.moves.clear();
+                        if self.captures.is_empty() {
+                            self.state = SortingState::Killers;
+                            continue;
+                        }
+                    }
+
+                    // lower mvvlva score is better
+                    let mut best_mvv_lva = crate::evaluate::MAX_VALUE;
+                    let mut best_move: Option<Move> = None;
+
+                    for c in &self.captures {
+                        let score = mvv_lva_score(c);
+                        if score < best_mvv_lva {
+                            best_move = Some(*c);
+                            best_mvv_lva = score;
+                        }
+                    }
+
+                    self.captures.retain(|m| Some(*m) != best_move);
+                    if self.captures.is_empty() {
+                        self.state = SortingState::Killers;
+                    }
+                    return best_move;
+                },
+                SortingState::Killers => {
+                    for k in &self.killers {
+                        if self.quiets.contains(k) {
+                            self.quiets.retain(|m| *m != *k);
+                            return Some(*k);
+                        }
+                    }
+                    self.state = SortingState::Quiets;
+                },
+                SortingState::Quiets => {
+                    return self.quiets.pop();
+                },
+            }
+        }
+
+        return None;
+    }
+}
+
 pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
 
     let mut moves: Vec<Move> = Vec::with_capacity(128);
@@ -209,7 +317,7 @@ fn generate_all_slides(origin: Bitboard) -> Bitboard {
     let mut se = origin;
     let mut nw = origin;
     let mut sw = origin;
-    for i in 1..7 {
+    for _ in 1..7 {
         result |= ne;
         result |= se;
         result |= nw;
@@ -223,8 +331,13 @@ fn generate_all_slides(origin: Bitboard) -> Bitboard {
 }
 
 
-pub fn generate_legal_moves(game: &mut Game, side: Side) -> Vec<Move> {
-    let moves = generate_moves(game, side);
+pub fn generate_legal_moves(game: &mut Game, side: Side, captures_only: bool) -> Vec<Move> {
+    let moves =
+        if captures_only {
+            generate_attacking_moves(game, side)
+        } else {
+            generate_moves(game, side)
+        };
 
     let check = is_check(game, side);
     let king = game.kings(side);
@@ -253,7 +366,7 @@ pub fn generate_legal_moves(game: &mut Game, side: Side) -> Vec<Move> {
 
 
 pub fn generate_legal_sorted_moves(game: &mut Game, _hash: &mut Cache, killers: &[Move], ce: Option<CacheEntry>, side: Side) -> Vec<Move> {
-    let mut moves = generate_legal_moves(game, side);
+    let mut moves = generate_legal_moves(game, side, false);
 
     let mov_val= |mov: &Move| {
         // if its a pv move from previously

+ 12 - 4
src/search.rs

@@ -171,17 +171,24 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
     }
 
     let ply_depth = (sc.initial_depth - depth) as usize;
-    let moves = generate_legal_sorted_moves(
+    /*let moves = generate_legal_sorted_moves(
         game,
         hash,
         &sc.killer_moves[ply_depth],
         cache_entry,
-        game.turn);
+        game.turn);*/
+
+    let moves = MoveGenerator::generate_legal_moves(
+        game,
+        cache_entry.as_ref(),
+        &sc.killer_moves[ply_depth],
+        game.turn
+    );
 
     //info!("nega moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
 
     let check = is_check(game, game.turn);
-    if moves.len() == 0 {
+    if moves.is_empty() {
         if check {
             // mate
             return -mate();
@@ -220,6 +227,7 @@ pub fn negamax(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache, mut al
     }
 
     for mov in moves {
+        //println!("mov: {}", mov.to_string());
         let undo = game.apply(mov);
 
         let val = -negamax(game, sc, hash, -decrease_mate_in(beta), -decrease_mate_in(alpha), depth - 1);
@@ -307,7 +315,7 @@ fn quiescence_search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache,
 
 
 pub fn perft(game: &mut Game, sc: &mut SearchControl, depth: i32) -> bool {
-    let moves = generate_legal_moves(game, game.turn);
+    let moves = generate_legal_moves(game, game.turn, false);
 
     if depth <= 1 {
         sc.nodes += moves.len();