|  | @@ -3,7 +3,9 @@ use bitboard::Square;
 | 
											
												
													
														|  |  use bitboard::*;
 |  |  use bitboard::*;
 | 
											
												
													
														|  |  use game::Game;
 |  |  use game::Game;
 | 
											
												
													
														|  |  use hash::{Cache, EntryType};
 |  |  use hash::{Cache, EntryType};
 | 
											
												
													
														|  | 
 |  | +use std::iter::Iterator;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +use crate::evaluate::evaluate;
 | 
											
												
													
														|  |  use crate::hash::CacheEntry;
 |  |  use crate::hash::CacheEntry;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  pub type Side = bool;
 |  |  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> {
 |  |  pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      let mut moves: Vec<Move> = Vec::with_capacity(128);
 |  |      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 se = origin;
 | 
											
												
													
														|  |      let mut nw = origin;
 |  |      let mut nw = origin;
 | 
											
												
													
														|  |      let mut sw = origin;
 |  |      let mut sw = origin;
 | 
											
												
													
														|  | -    for i in 1..7 {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    for _ in 1..7 {
 | 
											
												
													
														|  |          result |= ne;
 |  |          result |= ne;
 | 
											
												
													
														|  |          result |= se;
 |  |          result |= se;
 | 
											
												
													
														|  |          result |= nw;
 |  |          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 check = is_check(game, side);
 | 
											
												
													
														|  |      let king = game.kings(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> {
 |  |  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| {
 |  |      let mov_val= |mov: &Move| {
 | 
											
												
													
														|  |          // if its a pv move from previously
 |  |          // if its a pv move from previously
 |