|
@@ -2,12 +2,10 @@ use bitboard::Bitboard;
|
|
|
use bitboard::Square;
|
|
|
use bitboard::*;
|
|
|
use game::Game;
|
|
|
-use hash::{Cache, EntryType};
|
|
|
-use std::f32::consts::PI;
|
|
|
+use ttable::{Cache, EntryType};
|
|
|
use std::iter::Iterator;
|
|
|
|
|
|
-use crate::evaluate::evaluate;
|
|
|
-use crate::hash::CacheEntry;
|
|
|
+use crate::ttable::CacheEntry;
|
|
|
|
|
|
pub type Side = bool;
|
|
|
|
|
@@ -30,6 +28,11 @@ pub struct SimpleMove {
|
|
|
pub to: Square,
|
|
|
}
|
|
|
|
|
|
+///
|
|
|
+/// stores a PieceType and an additional Option<PieceType> in one single byte
|
|
|
+/// (under the assumption that there are only 6 pieces). This allows the Mov
|
|
|
+/// structure to be 4 bytes only
|
|
|
+///
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
pub struct PieceCaptureType(u8);
|
|
|
|
|
@@ -206,8 +209,6 @@ enum SortingState {
|
|
|
/// generates and sorts moves which can then be extracted via an Iterator interface
|
|
|
///
|
|
|
pub struct MoveGenerator {
|
|
|
-
|
|
|
- game: Game,
|
|
|
moves: Vec<Move>,
|
|
|
|
|
|
captures: Vec<Move>,
|
|
@@ -222,10 +223,9 @@ pub struct MoveGenerator {
|
|
|
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(),
|
|
|
+ captures: Vec::with_capacity(32),
|
|
|
+ quiets: Vec::with_capacity(32),
|
|
|
state: if ce.is_some() { SortingState::PvMove } else { SortingState::Captures },
|
|
|
pv_move: ce.map(|e| e.mov),
|
|
|
killers: killers.to_vec()
|
|
@@ -254,8 +254,14 @@ impl Iterator for MoveGenerator {
|
|
|
},
|
|
|
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();
|
|
|
+ for m in &self.moves {
|
|
|
+ if m.is_capture() {
|
|
|
+ self.captures.push(*m);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.quiets.push(*m);
|
|
|
+ }
|
|
|
+ }
|
|
|
self.moves.clear();
|
|
|
if self.captures.is_empty() {
|
|
|
self.state = SortingState::Killers;
|
|
@@ -442,7 +448,7 @@ pub fn generate_legal_sorted_moves(game: &mut Game, _hash: &mut Cache, killers:
|
|
|
let mov_val= |mov: &Move| {
|
|
|
// if its a pv move from previously
|
|
|
if let Some(c) = &ce {
|
|
|
- if &c.mov == mov {
|
|
|
+ if c.mov == *mov {
|
|
|
return -2000;
|
|
|
}
|
|
|
};
|
|
@@ -480,10 +486,10 @@ pub fn sort_moves(game: &mut Game, hash: &mut Cache, killers: &[Move], move_list
|
|
|
return e.value;
|
|
|
}
|
|
|
else if let EntryType::LowerBound = e.entry_type {
|
|
|
- return e.value - 1000;
|
|
|
+ return e.value + 1000;
|
|
|
}
|
|
|
else if let EntryType::UpperBound = e.entry_type {
|
|
|
- return e.value + 1000;
|
|
|
+ return e.value - 1000;
|
|
|
}
|
|
|
else {
|
|
|
return crate::evaluate::evaluate(game) - if killers.contains(mov) { 200 } else { 0 };
|
|
@@ -593,11 +599,11 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
let pawn_iterator = BitboardIterator(pawns);
|
|
|
|
|
|
for pawn in pawn_iterator {
|
|
|
- let left_cap = match side {
|
|
|
+ let right_cap = match side {
|
|
|
WHITE => northeast_one(pawn),
|
|
|
BLACK => southeast_one(pawn)
|
|
|
};
|
|
|
- let right_cap = match side {
|
|
|
+ let left_cap = match side {
|
|
|
WHITE => northwest_one(pawn),
|
|
|
BLACK => southwest_one(pawn)
|
|
|
};
|
|
@@ -766,13 +772,7 @@ fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, piec
|
|
|
let mask = if captures_only { others } else { !(0 as Bitboard) };
|
|
|
|
|
|
for piece in pieces_iter {
|
|
|
- let mut destinations: Bitboard = 0;
|
|
|
- if diagonal {
|
|
|
- destinations |= crate::magic::magic_bishop(square(piece), friends | others) & !friends;
|
|
|
- }
|
|
|
- if straight {
|
|
|
- destinations |= crate::magic::magic_rook(square(piece), friends | others) & !friends;
|
|
|
- }
|
|
|
+ let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
|
|
|
let dest_iter = BitboardIterator(destinations & mask);
|
|
|
for dest in dest_iter {
|
|
|
let smove = SimpleMove{ from: square(piece), to: square(dest) };
|
|
@@ -791,22 +791,16 @@ pub fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
|
|
|
diagonal: bool) -> Bitboard {
|
|
|
let occupied = friends | others;
|
|
|
|
|
|
- let straights = [north_one, south_one, east_one, west_one];
|
|
|
- let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
|
|
|
|
|
|
- let mut result: Bitboard = 0;
|
|
|
- if straight {
|
|
|
- for direction in straights.iter() {
|
|
|
- result |= generate_direction(piece, *direction, occupied);
|
|
|
- }
|
|
|
- }
|
|
|
+ let mut destinations: Bitboard = 0;
|
|
|
if diagonal {
|
|
|
- for direction in diagonals.iter() {
|
|
|
- result |= generate_direction(piece, *direction, occupied);
|
|
|
- }
|
|
|
+ destinations |= crate::magic::magic_bishop(square(piece), friends | others) & !friends;
|
|
|
}
|
|
|
-
|
|
|
- return result & !friends;
|
|
|
+ if straight {
|
|
|
+ destinations |= crate::magic::magic_rook(square(piece), friends | others) & !friends;
|
|
|
+ }
|
|
|
+
|
|
|
+ return destinations & !friends;
|
|
|
}
|
|
|
|
|
|
fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard) -> Bitboard {
|
|
@@ -841,15 +835,8 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captu
|
|
|
!friends
|
|
|
};
|
|
|
|
|
|
- let area = (north_one(king)
|
|
|
- | south_one(king)
|
|
|
- | east_one(king)
|
|
|
- | west_one(king)
|
|
|
- | northeast_one(king)
|
|
|
- | northwest_one(king)
|
|
|
- | southwest_one(king)
|
|
|
- | southeast_one(king))
|
|
|
- & mask;
|
|
|
+ let file = north_one(king) | king | south_one(king);
|
|
|
+ let area = (west_one(file) | file | east_one(file)) & mask;
|
|
|
|
|
|
let area_iter = BitboardIterator(area);
|
|
|
for destination in area_iter {
|
|
@@ -876,11 +863,8 @@ fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
//info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
|
|
|
if ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)) != 0 &&
|
|
|
((game.get_piece(KING, side) >> 1) | (game.get_piece(KING, side) >> 2)) & all_pieces == 0 {
|
|
|
- let mut tg1 = game.clone();
|
|
|
-
|
|
|
- *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) >> 1;
|
|
|
-
|
|
|
- if !is_check(game, side) && !is_check(&tg1, side) {
|
|
|
+ let king = game.get_piece(KING, side);
|
|
|
+ if !is_check(game, side) && !is_attacked(game, square(king) - 1, !side) {
|
|
|
move_list.push(c1);
|
|
|
}
|
|
|
}
|
|
@@ -890,14 +874,8 @@ fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
//info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
|
|
|
if ((game.get_piece(KING, side) << 4) & game.get_piece(ROOK, side)) != 0 &&
|
|
|
((game.get_piece(KING, side) << 1) | (game.get_piece(KING, side) << 2) | (game.get_piece(KING, side) << 3)) & all_pieces == 0 {
|
|
|
-
|
|
|
- let mut tg1 = game.clone();
|
|
|
- let mut tg2 = game.clone();
|
|
|
-
|
|
|
- *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) << 1;
|
|
|
- *tg2.get_piece_mut(KING, side) = game.get_piece(KING, side) << 2;
|
|
|
-
|
|
|
- if !is_check(game, side) && !is_check(&tg1, side) && !is_check(&tg2, side) {
|
|
|
+ let king = game.get_piece(KING, side);
|
|
|
+ if !is_check(game, side) && !is_attacked(game, square(king) + 1, !side) && !is_attacked(game, square(king) + 2, !side) {
|
|
|
move_list.push(c2);
|
|
|
}
|
|
|
}
|
|
@@ -1013,7 +991,7 @@ pub fn is_attacked(game: &Game, sq: Square, side: Side) -> bool {
|
|
|
mod tests {
|
|
|
use movegen::*;
|
|
|
|
|
|
- use crate::{search::{perft, SearchControl}, hash::RepetitionTable};
|
|
|
+ use crate::{search::{perft, SearchControl}, ttable::RepetitionTable};
|
|
|
|
|
|
///
|
|
|
/// tests the move generation from some positions to depth 4 and checks wether the correct
|