/// <summary> /// Construct board based on FEN. /// </summary> public Board(string Fen) { pieces = new int[64]; //Every square for every piece PvArray = new int[Defs.MaxDepth]; History = new HMove[2056]; for (int i = 0; i < History.Length; i++) { History[i] = new HMove(); } InitPVTable(); SearchHistory = new int[14][]; SearchKillers = new int[2][]; for (int i = 0; i < 14; i++) { SearchHistory[i] = new int[64]; } SearchKillers[0] = new int[Defs.MaxDepth]; SearchKillers[1] = new int[Defs.MaxDepth]; //Init board from FEN this.BoardFromFen(Fen); //Get hash key Position = Zobrist.GetHashPosition(this); UpdateOccupancy(); }
/// <summary> /// Makes a move. /// </summary> public void MakeMove(int move) { HMove hisMove = History[ply]; hisMove.castle = CastlePermission; hisMove.ep = (int)EnPassantSq; hisMove.move = move; hisMove.pos = Position; hisMove.fiftyMove = FiftyMove; //Move was made no more en passant square EnPassantSq = Squares.None; //increase it, but it may reset FiftyMove++; int From = move & 0x3f; int To = (move >> 6) & 0x3f; int movePiece = (move >> 12) & 0xf; //Removes the current castle permission from hash key since that might change during the move making Position ^= Zobrist.CastleRights[CastlePermission]; switch (movePiece) { #region WHITE case Defs.WPawn: //Moved to the desired position WPawn ^= Ops.Pow2[From]; WPawn |= Ops.Pow2[To]; //Zobrist Position ^= Zobrist.Pieces[From][Defs.WPawn]; Position ^= Zobrist.Pieces[To][Defs.WPawn]; //Reset fifty move FiftyMove = 0; pieces[From] = 0; pieces[To] = Defs.WPawn; if ((move & 0x700000) == 0x100000) // En passan capture { //Remove pawn BPawn ^= Ops.Pow2[To + 8]; pieces[To + 8] = 0; //Removes only Position ^= Zobrist.Pieces[To + 8][Defs.BPawn]; } else if (From - To == 16) //Double pawn move { EnPassantSq = (Squares)(To + 8); } else if ((move & 0x700000) > 0x200000) //Move is promotion { #region promo switch ((move >> 20) & 0xf) { case Defs.PromoQueen: WQueen ^= Ops.Pow2[To]; WPawn ^= Ops.Pow2[To]; pieces[To] = Defs.WQueen; Position ^= Zobrist.Pieces[To][Defs.WPawn]; Position ^= Zobrist.Pieces[To][Defs.WQueen]; break; case Defs.PromoBishop: WBishop ^= Ops.Pow2[To]; WPawn ^= Ops.Pow2[To]; pieces[To] = Defs.WBishop; Position ^= Zobrist.Pieces[To][Defs.WPawn]; Position ^= Zobrist.Pieces[To][Defs.WBishop]; break; case Defs.PromoKnight: WKnight ^= Ops.Pow2[To]; WPawn ^= Ops.Pow2[To]; pieces[To] = Defs.WKnight; Position ^= Zobrist.Pieces[To][Defs.WPawn]; Position ^= Zobrist.Pieces[To][Defs.WKnight]; break; case Defs.PromoRook: WRook ^= Ops.Pow2[To]; WPawn ^= Ops.Pow2[To]; pieces[To] = Defs.WRook; Position ^= Zobrist.Pieces[To][Defs.WPawn]; Position ^= Zobrist.Pieces[To][Defs.WRook]; break; } #endregion } break; case Defs.WBishop: WBishop ^= Ops.Pow2[From]; WBishop |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.WBishop]; Position ^= Zobrist.Pieces[To][Defs.WBishop]; pieces[From] = 0; pieces[To] = Defs.WBishop; break; case Defs.WKnight: WKnight ^= Ops.Pow2[From]; WKnight |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.WKnight]; Position ^= Zobrist.Pieces[To][Defs.WKnight]; pieces[From] = 0; pieces[To] = Defs.WKnight; break; case Defs.WRook: WRook ^= Ops.Pow2[From]; WRook |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.WRook]; Position ^= Zobrist.Pieces[To][Defs.WRook]; pieces[From] = 0; pieces[To] = Defs.WRook; if (From == 56) { CastlePermission &= ~Defs.CastleRightsQWCa; } else if (From == 63) { CastlePermission &= ~Defs.CastleRightsKWCa; } break; case Defs.WQueen: WQueen ^= Ops.Pow2[From]; WQueen |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.WQueen]; Position ^= Zobrist.Pieces[To][Defs.WQueen]; pieces[From] = 0; pieces[To] = Defs.WQueen; break; case Defs.WKing: WKing ^= Ops.Pow2[From]; WKing |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.WKing]; Position ^= Zobrist.Pieces[To][Defs.WKing]; pieces[From] = 0; pieces[To] = Defs.WKing; if ((move & 0x700000) == 0x200000) { if (To == 58) { WRook ^= Ops.Pow2[56]; WRook ^= Ops.Pow2[59]; pieces[56] = 0; pieces[59] = Defs.WRook; Position ^= Zobrist.Pieces[56][Defs.WRook]; Position ^= Zobrist.Pieces[59][Defs.WRook]; } else if (To == 62) { WRook ^= Ops.Pow2[61]; WRook ^= Ops.Pow2[63]; pieces[63] = 0; pieces[61] = Defs.WRook; Position ^= Zobrist.Pieces[61][Defs.WRook]; Position ^= Zobrist.Pieces[63][Defs.WRook]; } } CastlePermission &= ~(Defs.CastleRightsKWCa | Defs.CastleRightsQWCa); break; #endregion #region BLACK case Defs.BPawn: //Moved to the desired position BPawn ^= Ops.Pow2[From]; BPawn |= Ops.Pow2[To]; Position ^= Zobrist.Pieces[From][Defs.BPawn]; Position ^= Zobrist.Pieces[To][Defs.BPawn]; //Reset fifty move FiftyMove = 0; pieces[From] = 0; pieces[To] = Defs.BPawn; if ((move & 0x700000) == 0x100000) { //Remove pawn WPawn ^= Ops.Pow2[To - 8]; pieces[To - 8] = 0; //Removes only Position ^= Zobrist.Pieces[To + 8][Defs.BPawn]; } else if (From - To == -16) { EnPassantSq = (Squares)(To - 8); } else if ((move & 0x700000) > 0x200000) #region promo { switch ((move >> 20) & 0xf) { case Defs.PromoQueen: BQueen ^= Ops.Pow2[To]; BPawn ^= Ops.Pow2[To]; pieces[To] = Defs.BQueen; Position ^= Zobrist.Pieces[To][Defs.BPawn]; Position ^= Zobrist.Pieces[To][Defs.BQueen]; break; case Defs.PromoBishop: BBishop ^= Ops.Pow2[To]; BPawn ^= Ops.Pow2[To]; pieces[To] = Defs.BBishop; Position ^= Zobrist.Pieces[To][Defs.BPawn]; Position ^= Zobrist.Pieces[To][Defs.BBishop]; break; case Defs.PromoKnight: BKnight ^= Ops.Pow2[To]; BPawn ^= Ops.Pow2[To]; pieces[To] = Defs.BKnight; Position ^= Zobrist.Pieces[To][Defs.BPawn]; Position ^= Zobrist.Pieces[To][Defs.BKnight]; break; case Defs.PromoRook: BRook ^= Ops.Pow2[To]; BPawn ^= Ops.Pow2[To]; pieces[To] = Defs.BRook; Position ^= Zobrist.Pieces[To][Defs.BPawn]; Position ^= Zobrist.Pieces[To][Defs.BRook]; break; } } #endregion break; case Defs.BBishop: BBishop ^= Ops.Pow2[From]; BBishop |= Ops.Pow2[To]; pieces[From] = 0; pieces[To] = Defs.BBishop; Position ^= Zobrist.Pieces[From][Defs.BBishop]; Position ^= Zobrist.Pieces[To][Defs.BBishop]; break; case Defs.BKnight: BKnight ^= Ops.Pow2[From]; BKnight ^= Ops.Pow2[To]; pieces[From] = 0; pieces[To] = Defs.BKnight; Position ^= Zobrist.Pieces[From][Defs.BKnight]; Position ^= Zobrist.Pieces[To][Defs.BKnight]; break; case Defs.BRook: BRook ^= Ops.Pow2[From]; BRook |= Ops.Pow2[To]; pieces[From] = 0; pieces[To] = Defs.BRook; Position ^= Zobrist.Pieces[From][Defs.BRook]; Position ^= Zobrist.Pieces[To][Defs.BRook]; if (From == 0) { CastlePermission &= ~Defs.CastleRightsQBCa; } else if (From == 7) { CastlePermission &= ~Defs.CastleRightsKBCa; } break; case Defs.BQueen: BQueen ^= Ops.Pow2[From]; BQueen |= Ops.Pow2[To]; pieces[From] = 0; pieces[To] = Defs.BQueen; Position ^= Zobrist.Pieces[From][Defs.BQueen]; Position ^= Zobrist.Pieces[To][Defs.BQueen]; break; case Defs.BKing: BKing ^= Ops.Pow2[From]; BKing |= Ops.Pow2[To]; pieces[From] = 0; pieces[To] = Defs.BKing; Position ^= Zobrist.Pieces[From][Defs.BKing]; Position ^= Zobrist.Pieces[To][Defs.BKing]; if ((move & 0x700000) == 0x200000) { if (To == 2) { BRook ^= Ops.Pow2[3]; BRook ^= Ops.Pow2[0]; pieces[0] = 0; pieces[3] = Defs.BRook; Position ^= Zobrist.Pieces[0][Defs.BRook]; Position ^= Zobrist.Pieces[3][Defs.BRook]; } else if (To == 6) { BRook ^= Ops.Pow2[5]; BRook ^= Ops.Pow2[7]; pieces[7] = 0; pieces[5] = Defs.BRook; Position ^= Zobrist.Pieces[5][Defs.BRook]; Position ^= Zobrist.Pieces[7][Defs.BRook]; } } CastlePermission &= ~(Defs.CastleRightsKBCa | Defs.CastleRightsQBCa); break; #endregion } if ((move & 0xf0000) != 0) //Move was capture { #region capture switch ((move >> 16) & 0xf) { #region white case Defs.WPawn: WPawn ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.WPawn]; break; case Defs.WKnight: WKnight ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.WKnight]; break; case Defs.WBishop: WBishop ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.WKnight]; break; case Defs.WRook: WRook ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.WRook]; if (To == 56) { CastlePermission &= ~Defs.CastleRightsQWCa; } else if (To == 63) { CastlePermission &= ~Defs.CastleRightsKWCa; } break; case Defs.WQueen: WQueen ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.WQueen]; break; #endregion #region black case Defs.BPawn: BPawn ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.BPawn]; break; case Defs.BKnight: BKnight ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.BKnight]; break; case Defs.BBishop: BBishop ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.BBishop]; break; case Defs.BRook: BRook ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.BRook]; if (To == 0) { CastlePermission &= ~Defs.CastleRightsQBCa; } else if (To == 7) { CastlePermission &= ~Defs.CastleRightsKBCa; } break; case Defs.BQueen: BQueen ^= Ops.Pow2[To]; Position ^= Zobrist.Pieces[To][Defs.BQueen]; break; #endregion } #endregion //Reset fifty move FiftyMove = 0; } //Castle permission Position ^= Zobrist.CastleRights[CastlePermission]; Position ^= Zobrist.CastleRights[SideToPlay]; //Side to play SideToPlay = 1 - SideToPlay; Position ^= Zobrist.CastleRights[SideToPlay]; //Updates occupancy BOcc = BPawn | BBishop | BKnight | BRook | BQueen | BKing; WOcc = WPawn | WBishop | WKnight | WRook | WQueen | WKing; History[ply] = hisMove; ply++; }
public void UndoMove() { if (ply == 0) //No moves to undo { return; } ply--; HMove hisMove = History[ply]; int move = hisMove.move; int From = move & 0x3f; int To = (move >> 6) & 0x3f; int movePiece = (move >> 12) & 0xf; switch (movePiece) { #region WHITE case Defs.WPawn: if ((move & 0x700000) > 0x200000) { #region promo switch ((move >> 20) & 0xf) { case Defs.PromoQueen: WQueen ^= Ops.Pow2[To]; break; case Defs.PromoBishop: WBishop ^= Ops.Pow2[To]; break; case Defs.PromoKnight: WKnight ^= Ops.Pow2[To]; break; case Defs.PromoRook: WRook ^= Ops.Pow2[To]; break; } #endregion } else { WPawn ^= Ops.Pow2[To]; } //Moved to the desired position WPawn ^= Ops.Pow2[From]; pieces[To] = 0; pieces[From] = Defs.WPawn; if (move.IsEnPassantCapt()) { BPawn ^= Ops.Pow2[To + 8]; pieces[To + 8] = Defs.BPawn; } break; case Defs.WBishop: WBishop ^= Ops.Pow2[From]; WBishop ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.WBishop; break; case Defs.WKnight: WKnight ^= Ops.Pow2[From]; WKnight ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.WKnight; break; case Defs.WRook: WRook ^= Ops.Pow2[From]; WRook ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.WRook; break; case Defs.WQueen: WQueen ^= Ops.Pow2[From]; WQueen ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.WQueen; break; case Defs.WKing: WKing ^= Ops.Pow2[From]; WKing ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.WKing; if ((move & 0x700000) == 0x200000) { if (To == 58) { WRook ^= Ops.Pow2[56]; WRook ^= Ops.Pow2[59]; pieces[56] = Defs.WRook; pieces[59] = Defs.Empty; } else if (To == 62) { WRook ^= Ops.Pow2[61]; WRook ^= Ops.Pow2[63]; pieces[63] = Defs.WRook; pieces[61] = Defs.Empty; } } break; #endregion #region BLACK case Defs.BPawn: if ((move & 0x700000) > 0x200000) { #region promo switch ((move >> 20) & 0xf) { case Defs.PromoQueen: BQueen ^= Ops.Pow2[To]; break; case Defs.PromoBishop: BBishop ^= Ops.Pow2[To]; break; case Defs.PromoKnight: BKnight ^= Ops.Pow2[To]; break; case Defs.PromoRook: BRook ^= Ops.Pow2[To]; break; } #endregion } else { BPawn ^= Ops.Pow2[To]; } //Moved to the desired position BPawn ^= Ops.Pow2[From]; pieces[To] = 0; pieces[From] = Defs.BPawn; if (move.IsEnPassantCapt()) { WPawn ^= Ops.Pow2[To - 8]; pieces[To - 8] = Defs.WPawn; } break; case Defs.BBishop: BBishop ^= Ops.Pow2[From]; BBishop ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.BBishop; break; case Defs.BKnight: BKnight ^= Ops.Pow2[From]; BKnight ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.BKnight; break; case Defs.BRook: BRook ^= Ops.Pow2[From]; BRook ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.BRook; break; case Defs.BQueen: BQueen ^= Ops.Pow2[From]; BQueen ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.BQueen; break; case Defs.BKing: BKing ^= Ops.Pow2[From]; BKing ^= Ops.Pow2[To]; pieces[To] = 0; pieces[From] = Defs.BKing; if ((move & 0x700000) == 0x200000) { if (To == 2) { BRook ^= Ops.Pow2[3]; BRook ^= Ops.Pow2[0]; pieces[0] = Defs.BRook; pieces[3] = Defs.Empty; } else if (To == 6) { BRook ^= Ops.Pow2[5]; BRook ^= Ops.Pow2[7]; pieces[7] = Defs.BRook; pieces[5] = Defs.Empty; } } break; #endregion } if ((move & 0xf0000) != 0) { #region capture switch ((move >> 16) & 0xf) { #region white case Defs.WPawn: WPawn ^= Ops.Pow2[To]; pieces[To] = Defs.WPawn; break; case Defs.WKnight: WKnight ^= Ops.Pow2[To]; pieces[To] = Defs.WKnight; break; case Defs.WBishop: WBishop ^= Ops.Pow2[To]; pieces[To] = Defs.WBishop; break; case Defs.WRook: WRook ^= Ops.Pow2[To]; pieces[To] = Defs.WRook; break; case Defs.WQueen: WQueen ^= Ops.Pow2[To]; pieces[To] = Defs.WQueen; break; #endregion #region black case Defs.BPawn: BPawn ^= Ops.Pow2[To]; pieces[To] = Defs.BPawn; break; case Defs.BKnight: BKnight ^= Ops.Pow2[To]; pieces[To] = Defs.BKnight; break; case Defs.BBishop: BBishop ^= Ops.Pow2[To]; pieces[To] = Defs.BBishop; break; case Defs.BRook: BRook ^= Ops.Pow2[To]; pieces[To] = Defs.BRook; break; case Defs.BQueen: BQueen ^= Ops.Pow2[To]; pieces[To] = Defs.BQueen; break; #endregion } #endregion } //Updates occupancy BOcc = BPawn | BBishop | BKnight | BRook | BQueen | BKing; WOcc = WPawn | WBishop | WKnight | WRook | WQueen | WKing; CastlePermission = hisMove.castle; EnPassantSq = (Squares)hisMove.ep; Position = hisMove.pos; FiftyMove = hisMove.fiftyMove; SideToPlay = 1 - SideToPlay; }
public Move(HMove h, VMove v) { H = h; V = v; }