Sfoglia il codice sorgente

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

Nicolas Winkler 3 anni fa
parent
commit
3175ae248f
9 ha cambiato i file con 64 aggiunte e 174 eliminazioni
  1. 17 15
      src/bitboard.rs
  2. 4 0
      src/engine.rs
  3. 4 9
      src/game.rs
  4. 0 1
      src/hash.rs
  5. 1 3
      src/interface.rs
  6. 9 14
      src/main.rs
  7. 22 25
      src/movegen.rs
  8. 6 106
      src/search.rs
  9. 1 1
      src/zobrist.rs

+ 17 - 15
src/bitboard.rs

@@ -1,3 +1,5 @@
+
+
 /*!
  *
  * arranged like this:
@@ -6,18 +8,18 @@
  * 55 54 ...
  *
  */
+
 pub type Bitboard = u64;
 pub type Square = u8;
 
-
-pub const A_FILE: Bitboard = 0x_8080_8080_8080_8080;
-pub const B_FILE: Bitboard = A_FILE >> 1;
-pub const C_FILE: Bitboard = A_FILE >> 2;
-pub const D_FILE: Bitboard = A_FILE >> 3;
-pub const E_FILE: Bitboard = A_FILE >> 4;
-pub const F_FILE: Bitboard = A_FILE >> 5;
-pub const G_FILE: Bitboard = A_FILE >> 6;
-pub const H_FILE: Bitboard = A_FILE >> 7;
+pub const FILE_A: Bitboard = 0x_8080_8080_8080_8080;
+pub const FILE_B: Bitboard = FILE_A >> 1;
+pub const FILE_C: Bitboard = FILE_A >> 2;
+pub const FILE_D: Bitboard = FILE_A >> 3;
+pub const FILE_E: Bitboard = FILE_A >> 4;
+pub const FILE_F: Bitboard = FILE_A >> 5;
+pub const FILE_G: Bitboard = FILE_A >> 6;
+pub const FILE_H: Bitboard = FILE_A >> 7;
 
 pub const ROW_1: Bitboard = 0x_0000_0000_0000_00FF;
 pub const ROW_2: Bitboard = 0x_0000_0000_0000_FF00;
@@ -38,27 +40,27 @@ pub fn south_one(b: Bitboard) -> Bitboard {
 }
 
 pub fn west_one(b: Bitboard) -> Bitboard {
-    (b << 1) & !H_FILE
+    (b << 1) & !FILE_H
 }
 
 pub fn east_one(b: Bitboard) -> Bitboard {
-    (b >> 1) & !A_FILE
+    (b >> 1) & !FILE_A
 }
 
 pub fn northeast_one(b: Bitboard) -> Bitboard {
-    (b << 7) & !A_FILE
+    (b << 7) & !FILE_A
 }
 
 pub fn northwest_one(b: Bitboard) -> Bitboard {
-    (b << 9) & !H_FILE
+    (b << 9) & !FILE_H
 }
 
 pub fn southwest_one(b: Bitboard) -> Bitboard {
-    (b >> 7) & !H_FILE
+    (b >> 7) & !FILE_H
 }
 
 pub fn southeast_one(b: Bitboard) -> Bitboard {
-    (b >> 9) & !A_FILE
+    (b >> 9) & !FILE_A
 }
 
 pub fn bit_at_index(b: Bitboard, index: u32) -> bool {

+ 4 - 0
src/engine.rs

@@ -44,7 +44,10 @@ pub struct Engine {
     move_history: RepetitionTable,
     messages: VecDeque<EngineMsg>,
     r: Receiver<EngineMsg>,
+
+    #[allow(unused)]
     s: Sender<InterfaceMsg>,
+    
     hash: Cache,
     zobrist_table: Arc<ZobristTable>
 }
@@ -123,6 +126,7 @@ impl Engine {
         }
     }
 
+    #[allow(unused)]
     fn try_dequeue_message(&mut self) -> Option<EngineMsg> {
         if self.messages.is_empty() {
             self.r.try_recv().ok()

+ 4 - 9
src/game.rs

@@ -4,7 +4,6 @@ use log::info;
 use std::sync::Arc;
 use zobrist::{ZobristTable};
 use zobrist;
-use hash::RepetitionTable;
 
 #[derive(Clone)]
 pub struct Game
@@ -168,8 +167,7 @@ impl Game {
     }
 
     pub fn from_fen_str(fen: &str) -> Option<Game> {
-        let mut fen_parts = fen.split_whitespace();
-
+        let fen_parts = fen.split_whitespace();
         Self::from_fen(fen_parts.collect::<Vec<&str>>().as_slice())
     }
 
@@ -229,11 +227,11 @@ impl Game {
 
                     // pawn capture
                     let (from_file, from_row) = indices_from_square(from);
-                    let (to_file, to_row) = indices_from_square(to);
-                    if piece_type == PAWN && from_file != to_file {
+                    let (target_file, _target_row) = indices_from_square(to);
+                    if piece_type == PAWN && from_file != target_file {
                         let others = self.get_all_side(!side);
                         if others & from_square(to) == 0 {
-                            let beaten = square_from_indices(to_file, from_row);
+                            let beaten = square_from_indices(target_file, from_row);
                             return Ok(Move::EnPassant{ mov: SimpleMove{ from, to }, beaten });
                         }
                     }
@@ -592,11 +590,8 @@ impl Game {
         let en_passant_before = self.en_passant;
 
         let side = self.turn;
-        let friends = self.get_all_side(side);
         let others = self.get_all_side(!side);
 
-        let with_zobrist = self.zobrist.is_some();
-
         match mov {
             Move::Default{ mov, piece_type: pt, captured: _ } => {
 

+ 0 - 1
src/hash.rs

@@ -1,7 +1,6 @@
 use game::Game;
 use evaluate::PosValue;
 use std::collections::{HashMap};
-use std::hash::{BuildHasher, Hasher, Hash};
 use log::info;
 use zobrist;
 

+ 1 - 3
src/interface.rs

@@ -1,5 +1,3 @@
-
-use search::apply_move;
 use std::io::{self, BufRead};
 use std::collections::BTreeMap;
 use std::sync::mpsc::{Receiver, Sender};
@@ -54,7 +52,7 @@ fn cmd_isready(_args: Vec<&str>) {
     println!("readyok");
 }
 
-fn cmd_position(mut args: Vec<&str>, r: &Receiver<InterfaceMsg>, s: &Sender<EngineMsg>) {
+fn cmd_position(mut args: Vec<&str>, _r: &Receiver<InterfaceMsg>, s: &Sender<EngineMsg>) {
     let position = args[0];
     args.drain(0..1);
 

+ 9 - 14
src/main.rs

@@ -1,26 +1,21 @@
-mod interface;
-mod bitboard;
-mod movegen;
-mod engine;
-mod game;
-mod evaluate;
-mod search;
-mod zobrist;
-mod hash;
+pub mod interface;
+pub mod bitboard;
+pub mod movegen;
+pub mod engine;
+pub mod game;
+pub mod evaluate;
+pub mod search;
+pub mod zobrist;
+pub mod hash;
 
 extern crate log;
 extern crate simplelog;
 extern crate rand;
 
-use simplelog::*;
-
 use std::sync::mpsc;
 use std::{thread, fs::File};
-use log::*;
 use engine::Engine;
 
-use evaluate::*;
-
 fn main() {
     /*let mut builder = Builder::from_default_env();
     builder

+ 22 - 25
src/movegen.rs

@@ -3,7 +3,6 @@ use bitboard::Square;
 use bitboard::*;
 use game::Game;
 use hash::{Cache, EntryType};
-use log::info;
 
 pub type Side = bool;
 
@@ -26,8 +25,6 @@ pub struct SimpleMove {
     pub to: Square,
 }
 
-struct MovePieceTypes(u8);
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum Move {
     Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
@@ -177,13 +174,17 @@ pub fn generate_possattacking_moves(game: &Game, side: Side) -> Vec<Move> {
 }
 
 
-pub fn generate_legal_moves(game: &Game, side: Side) -> Vec<Move> {
+pub fn generate_legal_moves(game: &mut Game, side: Side) -> Vec<Move> {
     let moves = generate_moves(game, side);
 
-    moves.into_iter().filter(|mov| {
-        let tryout = crate::search::apply_move(game, *mov);
-        !is_check(&tryout, side)
-    }).collect::<Vec<Move>>()
+    let check_legality = |mov: &Move| {
+        let undo = game.apply(*mov);
+        let legal = !is_check(game, side);
+        game.undo_move(undo);
+        return legal;
+    };
+
+    moves.into_iter().filter(check_legality).collect::<Vec<Move>>()
 }
 
 
@@ -199,32 +200,29 @@ pub fn generate_attacking_moves(game: &Game, side: Side) -> Vec<Move> {
 }
 
 
-pub fn sort_moves(game: &Game, hash: &mut Cache, move_list: &mut Vec<Move>) {
-    let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
+pub fn sort_moves(game: &mut Game, hash: &mut Cache, move_list: &mut Vec<Move>) {
 
     move_list.sort_by_cached_key(|mov| {
-        let new_game = crate::search::apply_move(game, *mov);
-        if let Some(e) = hash.lookup(&new_game) {
+        let undo = game.apply(*mov);
+        if let Some(e) = hash.lookup(game) {
+            game.undo_move(undo);
             if let EntryType::Value = e.entry_type {
                 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 0;
             }
         }
         else {
-            return crate::evaluate::evaluate(&new_game);
-        }
-
-        match mov {
-            Move::Default { mov, piece_type: _, captured } => if let None = captured { 0 } else { -10 }, //if (from_square(mov.to) & all_pieces) != 0 { -10 } else { 0 },
-            Move::Castling { side: _, left: _ } => 0,
-            Move::Promotion { mov: _, promote_to: _, captured: _ } => -15,
-            Move::EnPassant { mov: _, beaten: _ } => -10,
-            Move::Nullmove => 0,
+            let eval = crate::evaluate::evaluate(game);
+            game.undo_move(undo);
+            return eval;
         }
     });
 }
@@ -336,7 +334,7 @@ fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
 
 fn generate_en_passant(game: &Game, side: Side, move_list: &mut Vec<Move>) {
     if let Some(ep) = game.en_passant {
-        let pawncolumn = A_FILE >> ep;
+        let pawncolumn = FILE_A >> ep;
 
         let pawnrow: Bitboard = match side {
             WHITE => ROW_5,
@@ -380,7 +378,6 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
         let nocap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & !others));
 
         for target in cap_targets {
-            let target_square = square(target);
             let simple_move = SimpleMove { from: square(k), to: square(target) };
             let captured = game.find_piece(target);
             move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });

+ 6 - 106
src/search.rs

@@ -1,4 +1,3 @@
-use bitboard::*;
 use movegen::*;
 use game::Game;
 use evaluate::*;
@@ -266,6 +265,12 @@ fn quiescence_search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache,
 
         let (mut val, ret) = quiescence_search(game, sc, hash, -beta, -alpha, depth - 1);
         val = -val;
+
+        if ret {
+            game.undo_move(undo);
+            return (alpha, ret)
+        }
+
         if val >= beta {
             game.undo_move(undo);
             return (beta, false);
@@ -279,111 +284,6 @@ fn quiescence_search(game: &mut Game, sc: &mut SearchControl, hash: &mut Cache,
 }
 
 
-pub fn apply_move(game: &Game, mov: Move) -> Game {
-    let mut new_game = game.clone();
-
-    let side = game.turn;
-    let friends = game.get_all_side(side);
-    let others = game.get_all_side(!side);
-    match mov {
-        Move::Default{ mov, piece_type: pt, captured: _ } => {
-
-            if pt == KING {
-                // invalidate castling rights
-                new_game.castling_rights[if game.turn == BLACK { 2 } else { 0 }] = false;
-                new_game.castling_rights[if game.turn == BLACK { 3 } else { 1 }] = false;
-            }
-
-            // invalidate castling rights
-            if mov.from == square_from_indices(7, 0) || mov.to == square_from_indices(7, 0) {
-                new_game.castling_rights[0] = false;
-            }
-            if mov.from == square_from_indices(0, 0) || mov.to == square_from_indices(0, 0) {
-                new_game.castling_rights[1] = false;
-            }
-            if mov.from == square_from_indices(7, 7) || mov.to == square_from_indices(7, 7) {
-                new_game.castling_rights[2] = false;
-            }
-            if mov.from == square_from_indices(0, 7) || mov.to == square_from_indices(0, 7) {
-                new_game.castling_rights[3] = false;
-            }
-
-            // if it is a capture
-            if from_square(mov.to) & others != 0 {
-                let (other_piece, other_side) = game.get_square(mov.to);
-                if let Some((ref zt, ref _zv)) = game.zobrist {
-                    let hup = zt.piece_hash(other_piece, other_side, mov.to);
-                    new_game.update_zobrist(hup);
-                }
-                new_game.apply_mask(!from_square(mov.to));
-            }
-
-            let moved_piece = mov.apply_to(new_game.get_piece(pt, side));
-            new_game.set_piece(pt, side, moved_piece);
-
-            if let Some((ref zt, ref _zv)) = game.zobrist {
-                let hup = zt.piece_hash(pt, side, mov.from) ^ zt.piece_hash(pt, side, mov.to);
-                new_game.update_zobrist(hup);
-            }
-        },
-        Move::Castling { side, left } => {
-            // invalidate future castling rights
-            new_game.castling_rights[if game.turn == BLACK { 2 } else { 0 }] = false;
-            new_game.castling_rights[if game.turn == BLACK { 3 } else { 1 }] = false;
-
-            let king = game.get_piece(KING, side);
-            let rook = if left {
-                game.get_piece(ROOK, side) & (king << 4)
-            }
-            else {
-                game.get_piece(ROOK, side) & (king >> 3)
-            };
-
-            let new_king = if left { king << 2 } else { king >> 2 };
-            let new_rook = if left { rook >> 3 } else { rook << 2 };
-
-            new_game.set_piece(KING, side, new_king);
-            *new_game.get_piece_mut(ROOK, side) |= new_rook;
-            *new_game.get_piece_mut(ROOK, side) &= !rook;
-        },
-        Move::EnPassant { mov, beaten } => {
-            let pawns = game.pawns(side);
-            if let Some(ep) = game.en_passant {
-                *new_game.get_piece_mut(PAWN, side) &= !from_square(mov.from);
-                *new_game.get_piece_mut(PAWN, side) |= from_square(mov.to);
-                *new_game.get_piece_mut(PAWN, !side) &= !from_square(beaten);
-            }
-        },
-        Move::Promotion { mov, promote_to, captured } => {
-            //if from_square(mov.to) & others != 0 {
-            if let Some(pt) = captured {
-                *new_game.get_piece_mut(pt, !side) &= !from_square(mov.to);
-            }
-            new_game.apply_mask(!from_square(mov.from));
-
-            match promote_to {
-                QUEEN => { *new_game.queens_mut(side) |= from_square(mov.to); }
-                ROOK => { *new_game.rooks_mut(side) |= from_square(mov.to); }
-                BISHOP => { *new_game.bishops_mut(side) |= from_square(mov.to); }
-                KNIGHT => { *new_game.knights_mut(side) |= from_square(mov.to); }
-                _ => {
-                    info!("internal error");
-                }
-            }
-        },
-        Move::Nullmove => {}
-    }
-
-    new_game.turn = !new_game.turn;
-
-
-    if let Some((ref zt, ref zv)) = new_game.zobrist {
-        //info!("applied {}, zobrist now {}", mov.to_string(), *zv);
-    }
-    return new_game;
-}
-
-
 pub fn perft(game: &mut Game, sc: &mut SearchControl, depth: i32) -> bool {
     let moves = generate_legal_moves(game, game.turn);
 

+ 1 - 1
src/zobrist.rs

@@ -1,6 +1,6 @@
 use rand::prelude::*;
 
-use movegen::{PieceType, Side, BLACK};
+use movegen::{PieceType};
 use bitboard::Square;
 
 pub type Hash = u64;