Nicolas Winkler 3 年之前
父节点
当前提交
31ca972d3a
共有 7 个文件被更改,包括 117 次插入45 次删除
  1. 10 5
      src/engine.rs
  2. 1 1
      src/evaluate.rs
  3. 26 2
      src/game.rs
  4. 5 1
      src/main.rs
  5. 13 24
      src/movegen.rs
  6. 3 1
      src/search.rs
  7. 59 11
      src/zobrist.rs

+ 10 - 5
src/engine.rs

@@ -6,7 +6,7 @@ use movegen::*;
 use evaluate::PosValue;
 use log::{info};
 use std::time::{Duration, Instant};
-use std::collections::VecDeque;
+use std::collections::{VecDeque, HashMap};
 
 use std::thread::sleep_ms;
 use std::sync::mpsc::{Receiver, Sender};
@@ -39,12 +39,16 @@ pub enum SearchInfo {
 pub enum InterfaceMsg {
 }
 
+pub struct HashEntry {
+
+}
 
 pub struct Engine {
     game: Game,
     messages: VecDeque<EngineMsg>,
     r: Receiver<EngineMsg>,
-    s: Sender<InterfaceMsg>
+    s: Sender<InterfaceMsg>,
+    hash: HashMap<Game, HashEntry>
 }
 
 impl Engine {
@@ -52,7 +56,8 @@ impl Engine {
         Engine {
             game: Game::default(),
             messages: VecDeque::new(),
-            r, s
+            r, s,
+            hash: HashMap::new()
         }
     }
 
@@ -100,7 +105,7 @@ impl Engine {
                 };
                 let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
                 let before = Instant::now();
-                let search_result = search(&self.game, &mut sc, *depth as i32);
+                let search_result = search(&self.game, &mut sc, &mut self.hash, *depth as i32);
 
                 if let SearchResult::Finished(best_move, best_val) = search_result {
                     let time = before.elapsed();
@@ -136,7 +141,7 @@ impl Engine {
                 let mut best_move = Move::default();
                 let mut best_val: PosValue = i32::max_value() as _;
                 loop {
-                    let search_result = search(&mut self.game, &mut sc, depth as i32);
+                    let search_result = search(&mut self.game, &mut sc, &mut self.hash, depth as i32);
                     if let SearchResult::Finished(bm, bv) = search_result {
                         info!("depth: {} bm: {}, bv: {}", depth, bm.to_string(), bv);
                         best_move = bm;

+ 1 - 1
src/evaluate.rs

@@ -28,7 +28,7 @@ fn value_castling_rights(game: &Game, side: Side) -> PosValue {
 
 fn side_value(game: &Game, side: Side) -> u32 {
     let knights = game.get_piece(KNIGHT, side);
-    let ks = BitboardIterator { board: knights };
+    let ks = BitboardIterator(knights);
     let mut k_attacks: u32 = 0;
 
     for k in ks {

+ 26 - 2
src/game.rs

@@ -1,6 +1,8 @@
 use bitboard::*;
 use movegen::*;
 use log::info;
+use zobrist::{ZobristTable};
+use zobrist;
 
 #[derive(Clone)]
 pub struct Game
@@ -417,7 +419,29 @@ impl Game {
         return board;
     }
 
-    pub fn calculate_zobrist(&self) -> u64 {
-        0
+    pub fn calculate_zobrist(&self, zt: &ZobristTable) -> zobrist::Hash {
+        let mut hash: zobrist::Hash = 0;
+        for pt in 0..12 {
+            let bb_it = BitboardIterator(self.pieces[pt]);
+            for bb_square in bb_it {
+                hash ^= zt.piece_hash(pt as _, square(bb_square));
+            }
+        }
+
+        for cr_id in 0..4 {
+            if self.castling_rights[cr_id] {
+                hash ^= zt.castling_rights_hash(cr_id as _);
+            }
+        }
+
+        if let Some(file) = self.en_passant {
+            hash ^= zt.en_passant_hash(file);
+        }
+
+        if self.turn {
+            hash ^= zt.turn_hash();
+        }
+
+        return hash;
     }
 }

+ 5 - 1
src/main.rs

@@ -1,3 +1,4 @@
+#![feature(build_hasher_simple_hash_one)]
 mod interface;
 mod bitboard;
 mod movegen;
@@ -6,6 +7,7 @@ mod game;
 mod evaluate;
 mod search;
 mod zobrist;
+mod hash;
 
 extern crate log;
 extern crate simplelog;
@@ -27,12 +29,14 @@ fn main() {
         .init();
         */
     
-    let logfile = File::create("C:\\\\Users\\Nicolas\\debug.log").unwrap();
+    let logfile = File::create("/home/nicolas/debug.log").unwrap();
     simplelog::WriteLogger::init(LevelFilter::Info, Config::default(), logfile).unwrap();
 
     let (esend, erecv) = mpsc::channel();
     let (isend, irecv) = mpsc::channel();
 
+    let zt = zobrist::ZobristTable::new();
+
     // spawn engine thread
     thread::spawn(move || {
         let mut engine = Engine::new(erecv, isend);

+ 13 - 24
src/movegen.rs

@@ -102,15 +102,15 @@ impl Move {
  *
  * Extracts every bit out of the bitboard and returns each one as a separate bitboard.
  */
-pub struct BitboardIterator { pub board: Bitboard }
+pub struct BitboardIterator (pub Bitboard);
 
 impl Iterator for BitboardIterator {
     type Item = Bitboard;
 
     fn next(&mut self) -> Option<Bitboard> {
-        if self.board != 0 {
-            let lsb = self.board & (self.board.wrapping_neg());
-            self.board ^= lsb;
+        if self.0 != 0 {
+            let lsb = self.0 & (self.0.wrapping_neg());
+            self.0 ^= lsb;
             //Some(lsb.trailing_zeros())
             Some(lsb)
         } else {
@@ -197,17 +197,6 @@ pub fn sort_moves(game: &Game, move_list: &mut Vec<Move>) {
 }
 
 
-/*
-pub fn generate_pawn_moves(game: &Game, side: Side) -> Bitboard {
-    let pushed = generate_pawn_pushes(game, side);
-    let iter = BitboardIterator { board: pushed };
-    for p in iter {
-        println!("{}", p.trailing_zeros());
-    }
-
-    return 0;
-}*/
-
 fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
     let pawns = game.pawns(side);
     let others = game.get_all_side(!side);
@@ -218,7 +207,7 @@ fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
             BLACK => south_one(pawns)
         } & !(ROW_1 | ROW_8) & !(others | pieces);
 
-    let iter = BitboardIterator { board: moved_pawns & !others };
+    let iter = BitboardIterator(moved_pawns & !others);
     for p in iter {
         let origin = match side {
             WHITE => south_one(p),
@@ -241,7 +230,7 @@ fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>
             BLACK => south_one(south_one(pawns) & !all_pieces)
         } & !all_pieces;
 
-    let iter = BitboardIterator { board: moved_pawns & !others };
+    let iter = BitboardIterator(moved_pawns & !others);
     for p in iter {
         let origin = match side {
             WHITE => south_one(south_one(p)),
@@ -256,7 +245,7 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
     let others = game.get_all_side(!side);
     let promotion_mask = ROW_1 | ROW_8;
 
-    let pawn_iterator = BitboardIterator { board: pawns };
+    let pawn_iterator = BitboardIterator(pawns);
 
     for pawn in pawn_iterator {
         let left_cap = match side {
@@ -295,7 +284,7 @@ fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
             BLACK => south_one(pawns)
         } & (ROW_1 | ROW_8) & !(others | pieces);
 
-    let iter = BitboardIterator { board: moved_pawns };
+    let iter = BitboardIterator(moved_pawns);
     for p in iter {
         let origin = match side {
             WHITE => south_one(p),
@@ -350,7 +339,7 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
     let others = game.get_all_side(!side);
 
     let knights = game.knights(side);
-    let knight_iter = BitboardIterator{ board: knights };
+    let knight_iter = BitboardIterator(knights);
 
     for k in knight_iter {
         let target_mask = if captures_only {
@@ -358,7 +347,7 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
         } else {
             !friends
         };
-        let targets = BitboardIterator { board: get_knight_targets(square(k)) & target_mask };
+        let targets = BitboardIterator(get_knight_targets(square(k)) & target_mask);
         for target in targets {
             let simple_move = SimpleMove { from: square(k), to: square(target) };
             move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT });
@@ -408,13 +397,13 @@ fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, capt
 
 fn generate_sliding_moves(friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
                           straight: bool, diagonal: bool, move_list: &mut Vec<Move>, captures_only: bool) {
-    let pieces_iter = BitboardIterator { board: pieces };
+    let pieces_iter = BitboardIterator(pieces);
 
     let mask = if captures_only { others } else { !(0 as Bitboard) };
 
     for piece in pieces_iter {
         let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
-        let dest_iter = BitboardIterator { board: destinations & mask };
+        let dest_iter = BitboardIterator(destinations & mask);
         for dest in dest_iter {
             let smove = SimpleMove{ from: square(piece), to: square(dest) };
             move_list.push(Move::Default { mov: smove, piece_type: piece_type});
@@ -487,7 +476,7 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captu
               | southeast_one(king))
             & mask;
 
-    let area_iter = BitboardIterator { board: area };
+    let area_iter = BitboardIterator(area);
     for destination in area_iter {
         let simple_move = SimpleMove{ from: square(king), to: square(destination) };
         move_list.push(Move::Default { mov: simple_move, piece_type: KING });

+ 3 - 1
src/search.rs

@@ -4,6 +4,8 @@ use game::Game;
 use evaluate::*;
 use log::info;
 use rand::prelude::*;
+use std::collections::HashMap;
+use engine::HashEntry;
 
 enum MoveUndo {
     Default {
@@ -37,7 +39,7 @@ pub enum SearchResult {
 /**
  * searches for moves and returns the best move found plus its value
  */
-pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> SearchResult {
+pub fn search(game: &Game, sc: &mut SearchControl, hash: &mut HashMap<Game, HashEntry>, depth: i32) -> SearchResult {
 
     if depth == 0 {
         return SearchResult::Invalid;

+ 59 - 11
src/zobrist.rs

@@ -1,18 +1,66 @@
+use rand::prelude::*;
 
+use movegen::{PieceType};
+use bitboard::Square;
 
-type Hash = u64;
+pub type Hash = u64;
 
-pub static table: [[Hash; 12]; 64] = initialize();
+pub struct ZobristTable {
+    board: [[Hash; 12]; 64],
+    en_passant: [Hash; 8],
+    castling_rights: [Hash; 4],
+    turn: Hash,
+}
 
-pub const fn initialize() -> [[Hash; 12]; 64] {
-    let mut val: u64 = 0xc7ad7b510a86ab2e_u64;
+impl ZobristTable {
 
-    let mut tab: [[Hash; 12]; 64] = [[0; 12]; 64];
+    pub fn new() -> Self {
+        let mut zt = ZobristTable {
+            board: [[0; 12]; 64],
+            en_passant: [0; 8],
+            castling_rights: [0; 4],
+            turn: 0
+        };
 
-    /*for piece in unsafe { &mut table } {
-        for sq in piece {
-            *sq = 3;
+        let seed: [u8; 32] =
+                [0x3f, 0x64, 0x5, 0x48, 0xef, 0x2d, 0xcb, 0x8e,
+                0xe6, 0x67, 0xc, 0x90, 0xcf, 0x10, 0x2d, 0x1e,
+                0x32, 0xb5, 0xbf, 0xe3, 0xf, 0x95, 0x8c, 0xf1,
+                0xbc, 0xe7, 0xb5, 0x76, 0x16, 0x4a, 0x17, 0x39];
+        let mut rng = StdRng::from_seed(seed);
+
+        for piece in &mut zt.board {
+            for sq in piece {
+                *sq = rng.next_u64();
+            }
+        }
+
+        for file in &mut zt.en_passant {
+            *file = rng.next_u64();
         }
-    }*/
-    tab
-}
+
+        for cr in &mut zt.castling_rights {
+            *cr = rng.next_u64();
+        }
+
+        zt.turn = rng.next_u64();
+
+        return zt;
+    }
+
+    pub fn piece_hash(&self, piece_type: PieceType, sq: Square) -> Hash {
+        self.board[sq as usize][piece_type as usize]
+    }
+
+    pub fn en_passant_hash(&self, file: u8) -> Hash {
+        self.en_passant[file as usize]
+    }
+
+    pub fn castling_rights_hash(&self, cr: u8) -> Hash {
+        self.castling_rights[cr as usize]
+    }
+
+    pub fn turn_hash(&self) -> Hash {
+        self.turn
+    }
+}