|
@@ -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
|