| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 | use bitboard::*;use movegen::*;use log::info;use std::sync::Arc;use zobrist::{ZobristTable, Hash};use crate::movegen;#[derive(Clone)]pub struct Board{    pub pieces: [Bitboard; 12],    pub turn: Side,    /// None if no en passant move is possible,    /// otherwise contains the file of the last (double-) pushed pawn    pub en_passant: Option<u8>,    ///    /// castling rights in the following order    /// white kingside, white queenside, black kingside, black queenside    ///     pub castling_rights: [bool; 4],    //    // non-hashed part    // vvv    pub turn_number: i32,    pub halfmoves_since_last_event: i8,    pub zobrist: Option<(Arc<ZobristTable>, Hash)>}impl Default for Board {    fn default () -> Board {        Board {            pieces: [                ROW_2,                0x42,                0x24,                0x81,                0x10,                0x08,                ROW_7,                0x42 << 56,                0x24 << 56,                0x81 << 56,                0x10 << 56,                0x08 << 56,            ],            turn: WHITE,            en_passant: None,            castling_rights: [true; 4],            halfmoves_since_last_event: 0,            turn_number: 0,            zobrist: None        }    }}impl std::hash::Hash for Board {    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {        if let Some((ref _zt, ref zb)) = &self.zobrist {            zb.hash(state);        }    }}impl PartialEq for Board {    fn eq(&self, other: &Self) -> bool {        self.pieces == other.pieces &&        self.turn == other.turn &&        self.en_passant == other.en_passant &&        self.castling_rights == other.castling_rights    }}impl Eq for Board {}impl Board {    pub fn empty() -> Board {        Board {            pieces: [0; 12],            turn: WHITE,            en_passant: None,            castling_rights: [true; 4],            halfmoves_since_last_event: 0,            turn_number: 0,            zobrist: None        }    }    pub fn from_fen(fen: &[&str]) -> Option<Board> {        let mut game: Board = Board::empty();        //let example = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";        let position = fen[0];        let turn = fen[1];        let castling_rights = fen[2];        let en_passant = fen[3];        let halfmoves_since_last_event = fen[4];        let turn_number = fen[5];        {            let rows = position.split('/');            let mut row_index: i32 = 7;            for row in rows {                if row_index < 0 {                    return None;                }                let mut col_index = 0;                for c in row.chars() {                    if col_index >= 8 {                        return None;                    }                    let bit_to_set = from_indices(col_index, row_index as _);                    match c {                        'p' => { *game.pawns_mut(BLACK) |= bit_to_set },                        'n' => { *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 },                        'N' => { *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;                }                row_index -= 1;            }        }        if turn == "b" {            game.turn = BLACK        }        // parse castling rights        game.castling_rights[0] = castling_rights.contains('K');        game.castling_rights[1] = castling_rights.contains('Q');        game.castling_rights[2] = castling_rights.contains('k');        game.castling_rights[3] = castling_rights.contains('q');        // parse en passant        game.en_passant = Move::parse_square(en_passant).map(|sq| indices_from_square(sq).0);        //info!("en passant on file {:?}", game.en_passant);        game.halfmoves_since_last_event = halfmoves_since_last_event.parse::<i8>().unwrap_or(0);        game.turn_number = turn_number.parse::<i32>().unwrap_or(0);                Some(game)    }    pub fn from_fen_str(fen: &str) -> Option<Board> {        let fen_parts = fen.split_whitespace();        Self::from_fen(fen_parts.collect::<Vec<&str>>().as_slice())    }    pub fn parse_move(&self, mov: &str) -> Result<Move, String> {        if mov.len() < 4 {            Err("string too short".to_owned())        }        else {            let origin = Move::parse_square(&mov[0..2]);            let target = Move::parse_square(&mov[2..4]);            let promote_to = if mov.len() == 5 {                Some(match mov.chars().nth(4) {                    Some('Q') | Some('q') => QUEEN,                    Some('N') | Some('n') => KNIGHT,                    Some('B') | Some('b') => BISHOP,                    Some('R') | Some('r') => ROOK,                    _ => return Err("invalid promotion".to_owned())                })            }            else {                None            };            if let (Some(from), Some(to)) = (origin, target) {                let (piece_type, side) = self.get_square(from).ok_or("no piece at from square")?;                //println!("from: {}", from);                let target = self.get_square(to);                let captured = if let Some((cap, _side)) = target { Some(cap) } else { None };                if let Some((_cap, cs)) = target {                    if cs == side {                        return Err("cannot capture own piece".to_owned());                    }                }                if side != self.turn {                    return Err("wrong side to move".to_owned());                }                if let Some(promote_to) = promote_to {                    if piece_type != PAWN {                        // should never happen                        return Err("cannot promote to pawn".to_owned());                    }                    Ok(Move::Promotion{ mov: SimpleMove{ from, to }, pc: PieceCaptureType::new(promote_to, captured) })                }                else {                    if piece_type == KING && (from as i32 - to as i32).abs() == 2 {                        let left = from < to;                        //println!("OMG castling!");                        return Ok(Move::Castling{ mov: SimpleMove { from, to }, side, left });                    }                    // pawn capture                    let (from_file, from_row) = indices_from_square(from);                    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(target_file, from_row);                            return Ok(Move::EnPassant{ mov: SimpleMove{ from, to }, beaten });                        }                    }                    //println!("pt: {}", piece_type);                    Ok(Move::Default{ mov: SimpleMove{ from, to }, pc: PieceCaptureType::new(piece_type, captured) })                }            }            else {                Err("no valid squares".to_owned())            }        }    }    pub fn bitboard(&self, pt: PieceType, side: Side) -> Bitboard {        if side == BLACK {            self.pieces[(pt + 6) as usize]        } else {            self.pieces[pt as usize]        }    }    /**     * finds the first bitboard that has overlapping bits with the given bitboard     * and returns the piece type of that bitboard     */    pub fn find_piece(&self, bitboard: Bitboard) -> Option<PieceType> {        for i in 0..12 {            if self.pieces[i] & bitboard != 0 {                return Some(if i >= 6 { i - 6 } else { i } as PieceType);            }        }        return None;    }    /**     * \return bitboard containig all occupied squares     */    pub fn occupied(&self) -> Bitboard {        self.pieces.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_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] |                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) -> Option<(PieceType, Side)> {        let square_mask = 1 << square;        for i in 0..6 {            if self.pieces[i] & square_mask != 0 {                return Some((i as PieceType, WHITE));            }        }        for i in 0..6 {            if self.pieces[i + 6] & square_mask != 0 {                return Some((i as PieceType, BLACK));            }        }        return None;    }    /**     * @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:     *     *   ┌───┬───┬───┬───┬───┬───┬───┬───┐     * 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 {                if let Some((pt, side)) = self.get_square(square_from_indices(i, 7 - row)) {                    let fig_index = pt as usize + if side == BLACK { 6 } else { 0 };                    line.push(figures[fig_index]);                }                else {                    line.push(' ');                }                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");        let chars = ['K', 'Q', 'k', 'q'];        let mut cr: [char; 4] = [' '; 4];        for i in 0..4 {            cr[i] = if self.castling_rights[i] {                chars[i]            } else { ' ' };        }        if self.turn == WHITE {            board.push_str("\nWhite to move\n");        }        else {            board.push_str("\nBlack to move\n");        }        board.push_str(&format!("\nCastling      : {}{}{}{}", cr[0], cr[1], cr[2], cr[3]));        board.push_str(&format!("\nEn Passant    : {}", self.en_passant.map(|f| f.to_string()).unwrap_or("-".to_owned())));        board.push_str(&format!("\nTurn number   : {}", self.turn_number));        board.push_str(&format!("\nHalfmoves slt : {}", self.halfmoves_since_last_event));        return board;    }    pub fn update_zobrist(&mut self, h: Hash) {        if let Some((ref _zt, ref mut zh)) = self.zobrist {            *zh ^= h;        }    }    pub fn calculate_zobrist(&self, zt: &ZobristTable) -> Hash {        let mut hash: Hash = 0;        for pt in 0..6 {            let bb_it_w = BitboardIterator(self.get_piece(pt, WHITE));            let bb_it_b = BitboardIterator(self.get_piece(pt, BLACK));            for bb_square in bb_it_w {                hash ^= zt.piece_hash(pt as _, WHITE, square(bb_square));            }            for bb_square in bb_it_b {                hash ^= zt.piece_hash(pt as _, BLACK, 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;    }    pub fn is_zobrist_correct(&self) -> bool {        if let Some((ref zt, zv)) = self.zobrist {            self.calculate_zobrist(zt) == zv        }        else {            false        }    }    ///    /// TODO: improve    ///     pub fn is_legal(&self, mov: Move) -> bool {        /*match mov {            Move::Default { mov, pc } => {                let piece_type = pc.piece_type();                let capture = pc.capture_type();                let legal_from = self.get_piece(piece_type, self.turn);                match piece_type {                    PAWN => {                        if pawn                    }                }            }        }*/        movegen::generate_legal_moves(&mut self.clone(), self.turn, false).contains(&mov)    }    pub fn apply(&mut self, mov: Move) -> MoveUndo {        /*if !self.is_zobrist_correct() {            println!("{}", self.beautiful_print());            println!("incorrect zobrist before apply {} {:?}", mov.to_string(), mov);            info!("incorrect zobrist before apply");            panic!("zobrist");            let val = if let Some((ref zt, _zv)) = self.zobrist {                self.calculate_zobrist(zt)            } else { 0 };            if let Some((ref _zt, ref mut zv)) = self.zobrist {                *zv = val;            }        }*/        // save irrecoverable values        let castling_rights_before = self.castling_rights.clone();        let halfmoves_since_last_event_before = self.halfmoves_since_last_event.clone();        let en_passant_before = self.en_passant;        let side = self.turn;        let others = self.get_all_side(!side);        if !mov.is_null() {            match mov {                Move::Default{ mov, pc } => {                    let pt = pc.piece_type();                    if pt == KING {                        // invalidate castling rights                        self.castling_rights[if side == BLACK { 2 } else { 0 }] = false;                        self.castling_rights[if side == BLACK { 3 } else { 1 }] = false;                    }                    // invalidate castling rights                    if mov.from == square_from_indices(7, 0) || mov.to == square_from_indices(7, 0) {                        self.castling_rights[0] = false;                    }                    if mov.from == square_from_indices(0, 0) || mov.to == square_from_indices(0, 0) {                        self.castling_rights[1] = false;                    }                    if mov.from == square_from_indices(7, 7) || mov.to == square_from_indices(7, 7) {                        self.castling_rights[2] = false;                    }                    if mov.from == square_from_indices(0, 7) || mov.to == square_from_indices(0, 7) {                        self.castling_rights[3] = false;                    }                    // if it is a capture                    if from_square(mov.to) & others != 0 {                        if let Some((other_piece, other_side)) = self.get_square(mov.to) {                            // update zobrist                            if let Some((ref zt, ref mut zv)) = self.zobrist {                                let hup = zt.piece_hash(other_piece, other_side, mov.to);                                *zv ^= hup;                            }                            *self.get_piece_mut(other_piece, other_side) &= !from_square(mov.to);                        }                    }                    // reset en passant and then check if possible                    self.en_passant = None;                    if pt == PAWN {                        let row1 = indices_from_square(mov.from).1;                        let row2 = indices_from_square(mov.to).1;                        // check for double push                        if i32::abs(row1 as i32 - row2 as i32) >= 2 {                            let opponent_pawns = self.get_piece(PAWN, !side);                            let target_bb = from_square(mov.to);                            if (west_one(target_bb) | east_one(target_bb)) & opponent_pawns != 0 {                                self.en_passant = Some(indices_from_square(mov.to).0);                            }                        }                    }                    let moved_piece = mov.apply_to(self.get_piece(pt, side));                    self.set_piece(pt, side, moved_piece);                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hup = zt.piece_hash(pt, side, mov.from) ^ zt.piece_hash(pt, side, mov.to);                        *zv ^= hup;                    }                },                Move::Castling { mov:_, side, left } => {                    // invalidate future castling rights                    self.castling_rights[if side == BLACK { 2 } else { 0 }] = false;                    self.castling_rights[if side == BLACK { 3 } else { 1 }] = false;                    let king = self.get_piece(KING, side);                    let rook = if left {                        self.get_piece(ROOK, side) & (king << 4)                    }                    else {                        self.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 };                    self.set_piece(KING, side, new_king);                    *self.get_piece_mut(ROOK, side) &= !rook;                    *self.get_piece_mut(ROOK, side) |= new_rook;                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hupk = zt.piece_hash(KING, side, square(king)) ^ zt.piece_hash(KING, side, square(new_king));                        let hup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(new_rook));                        *zv ^= hup ^ hupk;                    }                    self.en_passant = None;                },                Move::EnPassant { mov, beaten } => {                    if let Some(_ep) = self.en_passant {                        *self.get_piece_mut(PAWN, side) &= !from_square(mov.from);                        *self.get_piece_mut(PAWN, side) |= from_square(mov.to);                        *self.get_piece_mut(PAWN, !side) &= !from_square(beaten);                        if let Some((ref zt, ref mut zv)) = self.zobrist {                            let hup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(PAWN, side, mov.to);                            let hupo = zt.piece_hash(PAWN, !side, beaten);                            *zv ^= hup ^ hupo;                        }                        self.en_passant = None;                    }                    else {                        info!("internal en passant error");                        panic!("internal en passant error");                    }                },                Move::Promotion { mov, pc } => {                    let promote_to = pc.piece_type();                    let captured = pc.capture_type();                    //if from_square(mov.to) & others != 0 {                    if let Some(pt) = captured {                        *self.get_piece_mut(pt, !side) &= !from_square(mov.to);                        if let Some((ref zt, ref mut zv)) = self.zobrist {                            let hup = zt.piece_hash(pt, !side, mov.to);                            *zv ^= hup;                        }                    }                    *self.get_piece_mut(PAWN, side) &= !from_square(mov.from);                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hup = zt.piece_hash(PAWN, side, mov.from);                        *zv ^= hup;                    }                    match promote_to {                        QUEEN => { *self.queens_mut(side) |= from_square(mov.to); }                        ROOK => { *self.rooks_mut(side) |= from_square(mov.to); }                        BISHOP => { *self.bishops_mut(side) |= from_square(mov.to); }                        KNIGHT => { *self.knights_mut(side) |= from_square(mov.to); }                        _ => {                            info!("internal error");                        }                    }                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hup = zt.piece_hash(promote_to, side, mov.to);                        *zv ^= hup;                    }                    self.en_passant = None;                },            }        }        if self.turn == BLACK {            self.turn_number += 1;        }        self.turn = !self.turn;        if let Some((ref zt, ref mut zv)) = self.zobrist {            let hup = zt.turn_hash();            let castling_hup = zt.all_castling_rights_hash(castling_rights_before) ^ zt.all_castling_rights_hash(self.castling_rights);            let enpass_hup = en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0);            *zv ^= hup ^ castling_hup ^ enpass_hup;        }        /*if !self.is_zobrist_correct() {            println!("{}", self.beautiful_print());            println!("incorrect zobrist after apply {} {:?}", mov.to_string(), mov);            info!("incorrect zobrist after apply");            panic!("zobrist");            let val = if let Some((ref zt, _zv)) = self.zobrist {                self.calculate_zobrist(zt)            } else { 0 };            if let Some((ref _zt, ref mut zv)) = self.zobrist {                *zv = val;            }        }*/        MoveUndo {            castling_rights_before,            halfmoves_since_last_event_before,            en_passant_before,            mov        }    }    pub fn undo_move(&mut self, umov: MoveUndo) {        /*if !self.is_zobrist_correct() {            println!("{}", self.beautiful_print());            println!("incorrect zobrist before undo {} {:?}", umov.mov.to_string(), umov.mov);            info!("incorrect zobrist before undo {} {:?}", umov.mov.to_string(), umov.mov);            panic!("zobrist");        }*/        if let Some((ref zt, ref mut zv)) = self.zobrist {            let crhup = zt.all_castling_rights_hash(self.castling_rights) ^ zt.all_castling_rights_hash(umov.castling_rights_before);            let enpass_hup = self.en_passant.map(|f| zt.en_passant_hash(f)).unwrap_or(0) ^ umov.en_passant_before.map(|f| zt.en_passant_hash(f)).unwrap_or(0);            *zv ^= crhup ^ enpass_hup;        }        self.castling_rights = umov.castling_rights_before;        self.halfmoves_since_last_event = umov.halfmoves_since_last_event_before;        self.en_passant = umov.en_passant_before;                let mov = umov.mov;        // the side that played the turn that is to be reverted        let side = !self.turn;        if !mov.is_null() {            match mov {                Move::Default{ mov, pc } => {                    let piece_type = pc.piece_type();                    let captured = pc.capture_type();                    let moved_piece_bb = self.get_piece_mut(piece_type, side);                    *moved_piece_bb &= !from_square(mov.to);                    *moved_piece_bb |= from_square(mov.from);                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hup = zt.piece_hash(piece_type, side, mov.from) ^ zt.piece_hash(piece_type, side, mov.to);                        *zv ^= hup;                    }                    if let Some(pt) = captured {                        *self.get_piece_mut(pt, !side) |= from_square(mov.to);                        if let Some((ref zt, ref mut zv)) = self.zobrist {                            let hup = zt.piece_hash(pt, !side, mov.to);                            *zv ^= hup;                        }                    }                },                Move::Castling { mov: _, side, left } => {                    let king = self.get_piece(KING, side);                    let rook = if left {                        self.get_piece(ROOK, side) & (king >> 1)                    }                    else {                        self.get_piece(ROOK, side) & (king << 1)                    };                    let old_king = if left { king >> 2 } else { king << 2 };                    let old_rook = if left { rook << 3 } else { rook >> 2 };                    self.set_piece(KING, side, old_king);                    *self.get_piece_mut(ROOK, side) &= !rook;                    *self.get_piece_mut(ROOK, side) |= old_rook;                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let khup = zt.piece_hash(KING, side, square(old_king)) ^ zt.piece_hash(KING, side, square(king));                        let rhup = zt.piece_hash(ROOK, side, square(rook)) ^ zt.piece_hash(ROOK, side, square(old_rook));                        *zv ^= khup ^ rhup;                    }                },                Move::EnPassant { mov, beaten } => {                    *self.get_piece_mut(PAWN, side) |= from_square(mov.from);                    *self.get_piece_mut(PAWN, side) &= !from_square(mov.to);                    *self.get_piece_mut(PAWN, !side) |= from_square(beaten);                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let phup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(PAWN, side, mov.to);                        let chup = zt.piece_hash(PAWN, !side, beaten);                        *zv ^= phup ^ chup;                    }                    // should already be reverted                    //self.en_passant = Some(indices_from_square(beaten).0);                },                Move::Promotion { mov, pc } => {                    let promote_to = pc.piece_type();                    let captured = pc.capture_type();                    match promote_to {                        QUEEN => { *self.queens_mut(side) &= !from_square(mov.to); }                        ROOK => { *self.rooks_mut(side) &= !from_square(mov.to); }                        BISHOP => { *self.bishops_mut(side) &= !from_square(mov.to); }                        KNIGHT => { *self.knights_mut(side) &= !from_square(mov.to); }                        _ => {                            info!("internal error");                        }                    }                    *self.pawns_mut(side) |= from_square(mov.from);                    if let Some((ref zt, ref mut zv)) = self.zobrist {                        let hup = zt.piece_hash(PAWN, side, mov.from) ^ zt.piece_hash(promote_to, side, mov.to);                        *zv ^= hup;                    }                    if let Some(pt) = captured {                        *self.get_piece_mut(pt, !side) |= from_square(mov.to);                        if let Some((ref zt, ref mut zv)) = self.zobrist {                            let hup = zt.piece_hash(pt, !side, mov.to);                            *zv ^= hup;                        }                    }                },            }        }        self.turn = side;        if side == BLACK {            self.turn_number -= 1;        }        if let Some((ref zt, ref mut zv)) = self.zobrist {            *zv ^= zt.turn_hash();        }        /*if !self.is_zobrist_correct() {            println!("{}", self.beautiful_print());            println!("incorrect zobrist after undo {} {:?}", umov.mov.to_string(), umov.mov);            info!("incorrect zobrist after undo {} {:?}", umov.mov.to_string(), umov.mov);            panic!("zobrist");        }*/        /*let val = if let Some((ref zt, _zv)) = self.zobrist {            self.calculate_zobrist(zt)        } else { 0 };        if let Some((ref _zt, ref mut zv)) = self.zobrist {            *zv = val;        }*/    }        pub fn to_vector(&self) -> Vec<f64> {        let mut v = Vec::new();        for side in [WHITE, BLACK] {            for pt in 0..6 {                for sq in 0..64 {                    if self.get_square(sq) == Some((pt, side)) {                        v.push(1f64);                    }                    else {                        v.push(0f64);                    }                }            }        }        v    }    pub fn ply_number(&self) -> i32 {        self.turn_number * 2 + if self.turn == BLACK { 1 } else { 0 }    }}
 |