Explorar el Código

correcting move generation

Nicolas Winkler hace 3 años
padre
commit
1e771ce933
Se han modificado 6 ficheros con 134 adiciones y 21 borrados
  1. 2 1
      Cargo.lock
  2. 5 1
      src/bitboard.rs
  3. 6 5
      src/engine.rs
  4. 38 5
      src/game.rs
  5. 20 5
      src/movegen.rs
  6. 63 4
      src/search.rs

+ 2 - 1
Cargo.lock

@@ -1,4 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 [[package]]
 name = "bishop"
 version = "0.1.0"
-

+ 5 - 1
src/bitboard.rs

@@ -77,6 +77,10 @@ pub fn set_bit_index(b: &mut Bitboard, index: u32) {
     *b |= 1_u64 << index;
 }
 
+pub fn from_square(s: Square) -> Bitboard {
+    return 1_u64 << s;
+}
+
 pub fn square(b: Bitboard) -> Square {
     b.trailing_zeros() as Square
 }
@@ -85,7 +89,7 @@ pub fn square_from_indices(file: u8, row: u8) -> Square {
     (7 - row) * 8 + 7 - file
 }
 
-pub fn single_bit_board(file: u8, row: u8) -> Bitboard {
+pub fn from_indices(file: u8, row: u8) -> Bitboard {
     1_u64 << square_from_indices(file, row)
 }
 

+ 6 - 5
src/engine.rs

@@ -1,8 +1,10 @@
+use search::apply_move;
 use bitboard::Bitboard;
 use game::Game;
+use search::*;
+use movegen::*;
 
 use std::sync::mpsc::{Receiver, Sender};
-use movegen::*;
 
 pub enum EngineMsg {
     SetBoard([Bitboard; 12]),
@@ -36,10 +38,9 @@ pub fn run_engine(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) {
 
         println!("{}", game.beautiful_print());
 
-        let moves = generate_moves(&game, WHITE);
-        for mov in moves {
-            println!("move: {:?}", mov);
-        }
+        //let moves = generate_moves(&game, WHITE);
+        let best_move = search(&game, 2);
+        println!("bestmove {:?}", best_move);
     }
 }
 

+ 38 - 5
src/game.rs

@@ -1,6 +1,7 @@
 use bitboard::*;
 use movegen::*;
 
+#[derive(Clone)]
 pub struct Game
 {
     pub pieces: [Bitboard; 12],
@@ -53,7 +54,7 @@ impl Game {
                             return None;
                         }
 
-                        let bit_to_set = single_bit_board(col_index, row_index);
+                        let bit_to_set = from_indices(col_index, row_index);
                         match c {
                             'p' => { *game.pawns_mut(BLACK) |= bit_to_set },
                             'n' => { *game.knights_mut(BLACK) |= bit_to_set },
@@ -182,6 +183,27 @@ impl Game {
         }
     }
 
+    pub fn get_piece(&self, piece_type: PieceType, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[piece_type as usize],
+            BLACK => self.pieces[piece_type as usize + 6],
+        }
+    }
+
+    pub fn set_piece(&mut self, piece_type: PieceType, side: Side, bitboard: Bitboard) {
+        match side {
+            WHITE => self.pieces[piece_type as usize] = bitboard,
+            BLACK => self.pieces[piece_type as usize + 6] = bitboard,
+        }
+    }
+
+    pub fn get_piece_mut(&mut self, piece_type: PieceType, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[piece_type as usize],
+            BLACK => &mut self.pieces[piece_type as usize + 6],
+        }
+    }
+
     pub fn get_all_side(&self, side: Side) -> Bitboard {
         match side {
             WHITE => self.pieces[0] | self.pieces[1] | self.pieces[2] | self.pieces[3] |
@@ -197,6 +219,8 @@ impl Game {
             if self.pieces[i] & square_mask != 0 {
                 return (i as PieceType, WHITE);
             }
+        }
+        for i in 0..6 {
             if self.pieces[i + 6] & square_mask != 0 {
                 return (i as PieceType, BLACK);
             }
@@ -205,6 +229,15 @@ impl Game {
     }
 
     /**
+     * @brief masks all bitboards.
+     */
+    pub fn apply_mask(&mut self, mask: Bitboard) {
+        for board in &mut self.pieces {
+            *board &= mask;
+        }
+    }
+
+    /**
      * @brief creates a unicode string containing the board
      *
      * Example:
@@ -266,10 +299,10 @@ impl Game {
                 if pt == NO_PIECE {
                     line.push(' ');
                 }
-                    else {
-                        let fig_index = pt as usize + if side == BLACK { 6 } else { 0 };
-                        line.push(figures[fig_index]);
-                    }
+                else {
+                    let fig_index = pt as usize + if side == BLACK { 6 } else { 0 };
+                    line.push(figures[fig_index]);
+                }
                 line.push(' '); line.push(chars[1]); line.push(' ');
             }
             return line;

+ 20 - 5
src/movegen.rs

@@ -20,11 +20,11 @@ pub const KING: PieceType = 5;
 
 #[derive(Copy, Clone, Debug)]
 pub struct SimpleMove {
-    from: Square,
-    to: Square,
+    pub from: Square,
+    pub to: Square,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub enum Move {
     Default { mov: SimpleMove, piece_type: PieceType },
     Castling { side: Side, left: bool },
@@ -32,6 +32,12 @@ pub enum Move {
     Promotion { mov: SimpleMove, promote_to: PieceType },
 }
 
+impl Default for Move {
+    fn default() -> Move {
+        Move::Default{ mov: SimpleMove { from: 0, to: 0 }, piece_type: NO_PIECE }
+    }
+}
+
 /**
  * @brief Iterator to serialize bitboard bit for bit
  *
@@ -54,6 +60,12 @@ impl Iterator for BitboardIterator {
     }
 }
 
+impl SimpleMove {
+    pub fn apply_to(self, bitboard: Bitboard) -> Bitboard {
+        (bitboard & !from_square(self.from)) | from_square(self.to)
+    }
+}
+
 
 pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
     let mut moves: Vec<Move> = Vec::new();
@@ -265,7 +277,9 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
 
     let king = game.kings(side);
 
-    assert_eq!(king.count_ones(), 1); // assume only one king per player 
+    //assert_eq!(king.count_ones(), 1); // assume only one king per player 
+
+    if king.count_ones() != 1 { return; }
 
     let area = (north_one(king)
               | south_one(king)
@@ -284,6 +298,7 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
     }
 }
 
+/*
 #[cfg(test)]
 mod tests {
     use search::Game;
@@ -296,7 +311,7 @@ mod tests {
         assert_eq!(pawn_moves, ());
     }
 }
-
+*/
 
 
 

+ 63 - 4
src/search.rs

@@ -27,8 +27,24 @@ enum MoveUndo {
 //06         v := −negamax(child, depth − 1, −color)
 //07         bestValue := max( bestValue, v )
 //08     return bestValue
-pub fn search() {
+pub fn search(game: &Game, depth: i32) -> Move {
+    let mut best = i32::min_value();
+    let mut best_move = Move::default();
 
+    if depth == 0 {
+        return best_move;
+    }
+
+    let moves = generate_moves(game, game.turn);
+    for mov in moves {
+        let new_game = apply_move(game, mov);
+        let val = -negamax(&new_game, depth - 1);
+        if val > best {
+            best = val;
+            best_move = mov;
+        }
+    }
+    return best_move;
 }
 
 fn negamax(game: &Game, depth: i32) -> i32 {
@@ -36,14 +52,57 @@ fn negamax(game: &Game, depth: i32) -> i32 {
         return evaluate(game);
     }
 
-    let best = i32::min_value();
+    let mut best = i32::min_value();
+    let mut best_move = Move::default();
     let moves = generate_moves(game, game.turn);
     for mov in moves {
-
+        let new_game = apply_move(game, mov);
+        let val = -negamax(&new_game, depth - 1);
+        if val > best {
+            best = val;
+            best_move = mov;
+        }
     }
+    println!("bestmove {:?}", best_move);
     return 0;
 }
 
-fn apply_move(game: &Game, mov: Move) -> Game {
+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: mov, piece_type: pt } => {
+            if from_square(mov.to) | others != 0 {
+                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);
+        },
+        Move::Castling { side, left } => {
+            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.set_piece(ROOK, side, new_rook);
+        },
+        Move::EnPassant { side: side, column: col } => { panic!("oh no"); },
+        Move::Promotion { mov: mov, promote_to: pt } => { panic!("oh no"); },
+    }
+
+    new_game.turn = !new_game.turn;
+
+
 
+    return new_game;
 }