Nicolas Winkler 6 年之前
父節點
當前提交
ef3415a842
共有 6 個文件被更改,包括 331 次插入294 次删除
  1. 2 2
      src/engine.rs
  2. 7 0
      src/evaluate.rs
  3. 298 0
      src/game.rs
  4. 1 0
      src/main.rs
  5. 1 1
      src/movegen.rs
  6. 22 291
      src/search.rs

+ 2 - 2
src/engine.rs

@@ -1,11 +1,11 @@
 use bitboard::Bitboard;
-use search::Game;
+use game::Game;
 
 use std::sync::mpsc::{Receiver, Sender};
 use movegen::*;
 
 pub enum EngineMsg {
-    SetBoard,
+    SetBoard([Bitboard; 12]),
     SetPiece(Bitboard),
     Search(i32),
     Ping,

+ 7 - 0
src/evaluate.rs

@@ -0,0 +1,7 @@
+use game::*;
+
+
+fn evaluate(game: &Game) -> i32 {
+    return game.get_all_side(game.turn).count_ones()
+        - game.get_all_side(!game.turn).count_ones();
+}

+ 298 - 0
src/game.rs

@@ -0,0 +1,298 @@
+use bitboard::*;
+use movegen::*;
+
+pub struct Game
+{
+    pub pieces: [Bitboard; 12],
+    turn: Side,
+    en_passant: u8,
+}
+
+impl Default for Game {
+    fn default () -> Game {
+        Game {
+            pieces: [
+                ROW_2,
+                0x42,
+                0x24,
+                0x81,
+                0x10,
+                0x08,
+                ROW_7,
+                0x42 << 56,
+                0x24 << 56,
+                0x81 << 56,
+                0x10 << 56,
+                0x08 << 56,
+            ],
+            turn: WHITE,
+            en_passant: 0,
+        }
+    }
+}
+
+impl Game {
+
+    pub fn from_fen(fen: &str) -> Option<Game> {
+        let mut game: Game = Game::default();
+        let example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
+        let mut fen_parts = fen.split_whitespace();
+
+        match fen_parts.next() {
+            Some(position) => {
+                let rows = position.split('/');
+                let mut row_index = 0;
+                for row in rows {
+                    if row_index >= 8 {
+                        return None;
+                    }
+                    let mut col_index = 0;
+                    for c in row.chars() {
+
+                        if col_index >= 8 {
+                            return None;
+                        }
+
+                        let bit_to_set = single_bit_board(col_index, row_index);
+                        match c {
+                            'p' => { *game.pawns_mut(BLACK) |= bit_to_set },
+                            'k' => { *game.knights_mut(BLACK) |= bit_to_set },
+                            'b' => { *game.bishops_mut(BLACK) |= bit_to_set },
+                            'r' => { *game.rooks_mut(BLACK) |= bit_to_set },
+                            'q' => { *game.queens_mut(BLACK) |= bit_to_set },
+                            'k' => { *game.kings_mut(BLACK) |= bit_to_set },
+                            'P' => { *game.pawns_mut(WHITE) |= bit_to_set },
+                            'K' => { *game.knights_mut(WHITE) |= bit_to_set },
+                            'B' => { *game.bishops_mut(WHITE) |= bit_to_set },
+                            'R' => { *game.rooks_mut(WHITE) |= bit_to_set },
+                            'Q' => { *game.queens_mut(WHITE) |= bit_to_set },
+                            'K' => { *game.kings_mut(WHITE) |= bit_to_set },
+                            num => {
+                                col_index += match num.to_digit(10) { Some(x) => x, None => {
+                                    return None;
+                                }} as u8 - 1;
+                            }
+                        }
+                        col_index += 1;
+                    }
+                }
+            },
+            None => return None
+        }
+
+        None
+    }
+
+    pub fn bitboard(&self, pt: PieceType, side: Side) -> Bitboard {
+        if side == BLACK {
+            self.pieces[(pt + 6) as usize]
+        } else {
+            self.pieces[pt as usize]
+        }
+    }
+
+    /**
+     * \return bitboard containig all occupied squares
+     */
+    pub fn occupied(&self) -> Bitboard {
+        self.pieces.into_iter().fold(0, |a, b| { a | b } )
+    }
+
+    pub fn pawns(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[0],
+            BLACK => self.pieces[6],
+        }
+    }
+
+    pub fn knights(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[1],
+            BLACK => self.pieces[7],
+        }
+    }
+
+    pub fn bishops(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[2],
+            BLACK => self.pieces[8],
+        }
+    }
+
+    pub fn rooks(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[3],
+            BLACK => self.pieces[9],
+        }
+    }
+
+    pub fn queens(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[4],
+            BLACK => self.pieces[10],
+        }
+    }
+
+    pub fn kings(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[5],
+            BLACK => self.pieces[11],
+        }
+    }
+
+    pub fn pawns_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[0],
+            BLACK => &mut self.pieces[6],
+        }
+    }
+
+    pub fn knights_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[1],
+            BLACK => &mut self.pieces[7],
+        }
+    }
+
+    pub fn bishops_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[2],
+            BLACK => &mut self.pieces[8],
+        }
+    }
+
+    pub fn rooks_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[3],
+            BLACK => &mut self.pieces[9],
+        }
+    }
+
+    pub fn queens_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[4],
+            BLACK => &mut self.pieces[10],
+        }
+    }
+
+    pub fn kings_mut(&mut self, side: Side) -> &mut Bitboard {
+        match side {
+            WHITE => &mut self.pieces[5],
+            BLACK => &mut self.pieces[11],
+        }
+    }
+
+    pub fn get_all_side(&self, side: Side) -> Bitboard {
+        match side {
+            WHITE => self.pieces[0] | self.pieces[1] | self.pieces[2] | self.pieces[3] |
+                self.pieces[4] | self.pieces[5],
+            BLACK => self.pieces[6] | self.pieces[7] | self.pieces[8] | self.pieces[9] |
+                self.pieces[10] | self.pieces[11]
+        }
+    }
+
+    pub fn get_square(&self, square: Square) -> (PieceType, Side) {
+        let square_mask = 1 << square;
+        for i in 0..6 {
+            if self.pieces[i] & square_mask != 0 {
+                return (i as PieceType, WHITE);
+            }
+            if self.pieces[i + 6] & square_mask != 0 {
+                return (i as PieceType, BLACK);
+            }
+        }
+        return (NO_PIECE, WHITE);
+    }
+
+    /**
+     * @brief creates a unicode string containing the board
+     *
+     * Example:
+     *
+     *   ┌───┬───┬───┬───┬───┬───┬───┬───┐
+     * 8 │ ♜ │ ♞ │ ♝ │ ♛ │ ♚ │ ♝ │ ♞ │ ♜ │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 7 │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 6 │   │   │   │   │   │   │   │   │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 5 │   │   │   │   │   │   │   │   │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 4 │   │   │   │   │   │   │   │   │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 3 │   │   │   │   │   │   │   │   │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 2 │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │
+     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
+     * 1 │ ♖ │ ♘ │ ♗ │ ♕ │ ♔ │ ♗ │ ♘ │ ♖ │
+     *   └───┴───┴───┴───┴───┴───┴───┴───┘
+     *     a   b   c   d   e   f   g   h
+     *
+     */
+    pub fn beautiful_print(&self) -> String {
+        let chars = ['─', '│', '┌', '┐', '└', '┘', '├', '┤', '┬', '┴', '┼'];
+        let figures = ['♙', '♘', '♗', '♖', '♕', '♔', '♟', '♞', '♝', '♜', '♛', '♚'];
+        let mut board: String = String::new();
+
+        #[derive(Copy, Clone)]
+        struct GridLine {
+            left: char,
+            center: char,
+            right: char,
+        }
+
+        let top = GridLine { left: chars[2], center: chars[8], right: chars[3] };
+        let center = GridLine { left: chars[6], center: chars[10], right: chars[7] };
+        let bot = GridLine { left: chars[4], center: chars[9], right: chars[5] };
+
+        let generate_line = |gl: GridLine| {
+            let mut line = String::new();
+            for i in 0..33 {
+                match i {
+                    0 => { line.push(gl.left) }
+                    32 => { line.push(gl.right) }
+                    x => { line.push(if x % 4 == 0 { gl.center } else { chars[0] }) }
+                }
+            }
+            return line;
+        };
+
+        let piece_line = |row: u8| {
+            let mut line = String::new();
+            line.push(chars[1]);
+            line.push(' ');
+            for i in 0..8 {
+                let (pt, side) = self.get_square(square_from_indices(i, row));
+                if pt == NO_PIECE {
+                    line.push(' ');
+                }
+                    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;
+        };
+
+        board.push_str("  ");
+        board.push_str(&generate_line(top));
+        board.push('\n');
+        for i in 0..8 {
+            board.push_str(&(8 - i).to_string());
+            board.push(' ');
+            board.push_str(&piece_line(i));
+            board.push('\n');
+            if i != 7 {
+                board.push_str("  ");
+                board.push_str(&generate_line(center));
+                board.push('\n');
+            }
+        }
+        board.push_str("  ");
+        board.push_str(&generate_line(bot));
+        board.push_str("\n    a   b   c   d   e   f   g   h");
+
+        return board;
+    }
+}

+ 1 - 0
src/main.rs

@@ -2,6 +2,7 @@ mod interface;
 mod bitboard;
 mod movegen;
 mod engine;
+mod game;
 mod search;
 
 use std::sync::mpsc;

+ 1 - 1
src/movegen.rs

@@ -1,7 +1,7 @@
 use bitboard::Bitboard;
 use bitboard::Square;
 use bitboard::*;
-use search::Game;
+use game::Game;
 
 pub type Side = bool;
 

+ 22 - 291
src/search.rs

@@ -1,303 +1,34 @@
 use bitboard::*;
 use movegen::*;
 
+enum MoveUndo {
+    Default {
+        piece_type: PieceType,
+        before: Bitboard,
+        captured_type: PieceType,
+        captured_before: Bitboard,
+    },
+    Castling { rooks_before: Bitboard, king_before: Bitboard },
+    Promotion {
+        promoted_to: PieceType,
+        promoted_to_before: Bitboard,
 
-pub struct Game
-{
-    pub pieces: [Bitboard; 12],
-    en_passant: u8,
-}
-
-impl Default for Game {
-    fn default () -> Game {
-        Game {
-            pieces: [
-                ROW_2,
-                0x42,
-                0x24,
-                0x81,
-                0x10,
-                0x08,
-                ROW_7,
-                0x42 << 56,
-                0x24 << 56,
-                0x81 << 56,
-                0x10 << 56,
-                0x08 << 56,
-            ],
-            en_passant: 0,
-        }
-    }
-}
-
-impl Game {
-
-    pub fn from_fen(fen: &str) -> Option<Game> {
-        let mut game: Game = Game::default();
-        let example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
-        let mut fen_parts = fen.split_whitespace();
-
-        match fen_parts.next() {
-            Some(position) => {
-                let rows = position.split('/');
-                let mut row_index = 0;
-                for row in rows {
-                    if row_index >= 8 {
-                        return None;
-                    }
-                    let mut col_index = 0;
-                    for c in row.chars() {
-                        
-                        if col_index >= 8 {
-                            return None;
-                        }
-
-                        let bit_to_set = single_bit_board(col_index, row_index);
-                        match c {
-                            'p' => { *game.pawns_mut(BLACK) |= bit_to_set },
-                            'k' => { *game.knights_mut(BLACK) |= bit_to_set },
-                            'b' => { *game.bishops_mut(BLACK) |= bit_to_set },
-                            'r' => { *game.rooks_mut(BLACK) |= bit_to_set },
-                            'q' => { *game.queens_mut(BLACK) |= bit_to_set },
-                            'k' => { *game.kings_mut(BLACK) |= bit_to_set },
-                            'P' => { *game.pawns_mut(WHITE) |= bit_to_set },
-                            'K' => { *game.knights_mut(WHITE) |= bit_to_set },
-                            'B' => { *game.bishops_mut(WHITE) |= bit_to_set },
-                            'R' => { *game.rooks_mut(WHITE) |= bit_to_set },
-                            'Q' => { *game.queens_mut(WHITE) |= bit_to_set },
-                            'K' => { *game.kings_mut(WHITE) |= bit_to_set },
-                            num => {
-                                col_index += match num.to_digit(10) { Some(x) => x, None => {
-                                    return None;
-                                }} as u8 - 1;
-                            }
-                        }
-                        col_index += 1;
-                    }
-                }
-            },
-            None => return None
-        }
-
-        None
-    }
-
-    pub fn bitboard(&self, pt: PieceType, side: Side) -> Bitboard {
-        if side == BLACK {
-            self.pieces[(pt + 6) as usize]
-        } else {
-            self.pieces[pt as usize]
-        }
-    }
-
-    /**
-     * \return bitboard containig all occupied squares
-     */
-    pub fn occupied(&self) -> Bitboard {
-        self.pieces.into_iter().fold(0, |a, b| { a | b } )
-    }
-
-    pub fn pawns(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[0],
-            BLACK => self.pieces[6],
-        }
-    }
-
-    pub fn knights(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[1],
-            BLACK => self.pieces[7],
-        }
-    }
-
-    pub fn bishops(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[2],
-            BLACK => self.pieces[8],
-        }
-    }
-
-    pub fn rooks(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[3],
-            BLACK => self.pieces[9],
-        }
-    }
-
-    pub fn queens(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[4],
-            BLACK => self.pieces[10],
-        }
-    }
-
-    pub fn kings(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[5],
-            BLACK => self.pieces[11],
-        }
-    }
-
-    pub fn pawns_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[0],
-            BLACK => &mut self.pieces[6],
-        }
-    }
-
-    pub fn knights_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[1],
-            BLACK => &mut self.pieces[7],
-        }
-    }
-
-    pub fn bishops_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[2],
-            BLACK => &mut self.pieces[8],
-        }
-    }
-
-    pub fn rooks_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[3],
-            BLACK => &mut self.pieces[9],
-        }
-    }
-
-    pub fn queens_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[4],
-            BLACK => &mut self.pieces[10],
-        }
-    }
-
-    pub fn kings_mut(&mut self, side: Side) -> &mut Bitboard {
-        match side {
-            WHITE => &mut self.pieces[5],
-            BLACK => &mut self.pieces[11],
-        }
-    }
-
-    pub fn get_all_side(&self, side: Side) -> Bitboard {
-        match side {
-            WHITE => self.pieces[0] | self.pieces[1] | self.pieces[2] | self.pieces[3] |
-                self.pieces[4] | self.pieces[5],
-            BLACK => self.pieces[6] | self.pieces[7] | self.pieces[8] | self.pieces[9] |
-                self.pieces[10] | self.pieces[11]
-        }
-    }
-
-    pub fn get_square(&self, square: Square) -> (PieceType, Side) {
-        let square_mask = 1 << square;
-        for i in 0..6 {
-            if self.pieces[i] & square_mask != 0 {
-                return (i as PieceType, WHITE);
-            }
-            if self.pieces[i + 6] & square_mask != 0 {
-                return (i as PieceType, BLACK);
-            }
-        }
-        return (NO_PIECE, WHITE);
-    }
-
-    /**
-     * @brief creates a unicode string containing the board
-     *
-     * Example:
-     *
-     *   ┌───┬───┬───┬───┬───┬───┬───┬───┐
-     * 8 │ ♜ │ ♞ │ ♝ │ ♛ │ ♚ │ ♝ │ ♞ │ ♜ │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 7 │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │ ♟ │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 6 │   │   │   │   │   │   │   │   │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 5 │   │   │   │   │   │   │   │   │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 4 │   │   │   │   │   │   │   │   │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 3 │   │   │   │   │   │   │   │   │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 2 │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │ ♙ │
-     *   ├───┼───┼───┼───┼───┼───┼───┼───┤
-     * 1 │ ♖ │ ♘ │ ♗ │ ♕ │ ♔ │ ♗ │ ♘ │ ♖ │
-     *   └───┴───┴───┴───┴───┴───┴───┴───┘
-     *     a   b   c   d   e   f   g   h
-     *
-     */
-    pub fn beautiful_print(&self) -> String {
-        let chars = ['─', '│', '┌', '┐', '└', '┘', '├', '┤', '┬', '┴', '┼'];
-        let figures = ['♙', '♘', '♗', '♖', '♕', '♔', '♟', '♞', '♝', '♜', '♛', '♚'];
-        let mut board: String = String::new();
-
-        #[derive(Copy, Clone)]
-        struct GridLine {
-            left: char,
-            center: char,
-            right: char,
-        }
-
-        let top = GridLine { left: chars[2], center: chars[8], right: chars[3] };
-        let center = GridLine { left: chars[6], center: chars[10], right: chars[7] };
-        let bot = GridLine { left: chars[4], center: chars[9], right: chars[5] };
-
-        let generate_line = |gl: GridLine| {
-            let mut line = String::new();
-            for i in 0..33 {
-                match i {
-                    0 => { line.push(gl.left) }
-                    32 => { line.push(gl.right) }
-                    x => { line.push(if x % 4 == 0 { gl.center } else { chars[0] }) }
-                }
-            }
-            return line;
-        };
-
-        let piece_line = |row: u8| {
-            let mut line = String::new();
-            line.push(chars[1]);
-            line.push(' ');
-            for i in 0..8 {
-                let (pt, side) = self.get_square(square_from_indices(i, row));
-                if pt == NO_PIECE {
-                    line.push(' ');
-                }
-                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;
-        };
-
-        board.push_str("  ");
-        board.push_str(&generate_line(top));
-        board.push('\n');
-        for i in 0..8 {
-            board.push_str(&(8 - i).to_string());
-            board.push(' ');
-            board.push_str(&piece_line(i));
-            board.push('\n');
-            if i != 7 {
-                board.push_str("  ");
-                board.push_str(&generate_line(center));
-                board.push('\n');
-            }
-        }
-        board.push_str("  ");
-        board.push_str(&generate_line(bot));
-        board.push_str("\n    a   b   c   d   e   f   g   h");
-
-        return board;
     }
 }
 
+//01 function negamax(node, depth, color)
+//02     if depth = 0 or node is a terminal node
+//03         return color * the heuristic value of node
+//
+//04     bestValue := −∞
+//05     foreach child of node
+//06         v := −negamax(child, depth − 1, −color)
+//07         bestValue := max( bestValue, v )
+//08     return bestValue
 pub fn search() {
 
 }
 
+/*fn negamax(game: &Game, depth: i32) {
 
+}*/