public ChessPosition() { initChessEval(); Board = new SquareInfo[64]; emptyBoard = new SquareInfo[64]; Princ = new ChessMove[maxDepth, maxDepth]; killers = new ChessMove[2, 1000]; mvvLva = new int[8, 8]; searchHistory = new int[16, 64]; // Init the mvvLva array for (int v = 0; v <= 6; v++) for (int a = 0; a <= 6; a++) mvvLva[v, a] = v * 100 +6 - a; // Init the killers array for (int i = 0; i < 1000; i++) { killers[0, i] = new ChessMove(new Square(99, 99), new Square(99, 99)); killers[1, i] = new ChessMove(new Square(99, 99), new Square(99, 99)); } // Init the emptyBoard and Board arrays for (int i = 0; i <= 63; i++) { emptyBoard[i] = new SquareInfo(Pieces.None, new Square(i)); Board[i] = emptyBoard[i]; } // Init the hashKeys Random rng = new Random(); pieceKeys = new UInt64[16, 64]; for (int p = 0; p <= 15; p++) for (int sq = 0; sq <= 63; sq++) pieceKeys[p, sq] = (UInt64)rng.Next() + ((UInt64)rng.Next() << 15) + ((UInt64)rng.Next() << 30) + ((UInt64)rng.Next() << 45) + ((UInt64)rng.Next() << 60); castleKeys = new UInt64[16]; for (int i = 0; i <= 15; i++) castleKeys[i] = (UInt64)rng.Next() + ((UInt64)rng.Next() << 15) + ((UInt64)rng.Next() << 30) + ((UInt64)rng.Next() << 45) + ((UInt64)rng.Next() << 60); sideKey = (UInt64)rng.Next() + ((UInt64)rng.Next() << 15) + ((UInt64)rng.Next() << 30) + ((UInt64)rng.Next() << 45) + ((UInt64)rng.Next() << 60); // Init the pvTable pvTable = new Dictionary<ulong, int>(); EpSquare = new Square(0, 0); white = new ToMoveData(PieceColour.White, new Piece(PieceType.Pawn, PieceColour.White), new Piece(PieceType.Knight, PieceColour.White), new Piece(PieceType.Bishop, PieceColour.White), new Piece(PieceType.Rook, PieceColour.White), new Piece(PieceType.Queen, PieceColour.White), new Piece(PieceType.King, PieceColour.White), 1, 7, 1, CastleFlags.Wks, CastleFlags.Wqs, new Square("e1"), new Square("h1"), new Square("a1")); black = new ToMoveData(PieceColour.Black, new Piece(PieceType.Pawn, PieceColour.Black), new Piece(PieceType.Knight, PieceColour.Black), new Piece(PieceType.Bishop, PieceColour.Black), new Piece(PieceType.Rook, PieceColour.Black), new Piece(PieceType.Queen, PieceColour.Black), new Piece(PieceType.King, PieceColour.Black), 6, 0, -1, CastleFlags.Bks, CastleFlags.Bqs, new Square("e8"), new Square("h8"), new Square("a8")); PossibleMoves = new Collection<ChessMove>(); MoveHistory = new Collection<ChessMove>(); undoStack = new Stack<ChessMove>(); NewGame(); }
void updatePrinc(ChessMove move, int ply) { Princ[ply, ply] = move; for (int i = ply + 1; i < maxDepth; i++) Princ[ply, i] = Princ[ply + 1, i]; pvTable[HashKey] = (int)move.FromSq + ((int)move.ToSq << 8); }
void makeMove(ChessMove move) { Square from = move.FromSq; Square to = move.ToSq; SquareInfo CapturedSqInfo = Board[to]; Board[to] = Board[from]; // Move the piece Board[from] = emptyBoard[from]; // Replace from SquareInfo with the empty SquareInfo from emptyBoard Board[to].Location = to; // Update SqInfo location move.OldHashKey = HashKey; move.OldEpSq = EpSquare; EpSquare = new Square(0, 0); move.OldCastleFlags = CastleFlags; HashKey ^= pieceKeys[move.Piece.ToInt(), from] ^ pieceKeys[move.Piece.ToInt(), to]; bool pawnMoveOrCapture = false; switch (move.Special) { case SpecialMoveType.PawnMove: pawnMoveOrCapture = true; break; case SpecialMoveType.DoublePawnMove: EpSquare = new Square(from.File, from.Rank + thisSide.PawnYDir); pawnMoveOrCapture = true; break; case SpecialMoveType.Promotion: Board[to].Piece = move.PromotedTo; pawnMoveOrCapture = true; HashKey ^= pieceKeys[move.Piece.ToInt(), to] ^ pieceKeys[move.PromotedTo.ToInt(), to]; break; case SpecialMoveType.EnPassant: // After the piece has been moved make to = the square of the captured ep pawn to.Rank -= thisSide.PawnYDir; CapturedSqInfo = Board[to]; // CapturedSqInfo is the enemy pawn not the square moved into Board[to] = emptyBoard[to]; break; case SpecialMoveType.CastleKS: // Move the rook to = thisSide.RookKCastleSq; from = thisSide.KingRookSq; Board[to] = Board[from]; // Move the piece Board[from] = emptyBoard[from]; // Replace from SquareInfo with the empty SquareInfo from emptyBoard Board[to].Location = to; // Update SqInfo location HashKey ^= pieceKeys[Board[to].Piece.ToInt(), from] ^ pieceKeys[Board[to].Piece.ToInt(), to]; break; case SpecialMoveType.CastleQS: to = thisSide.RookQCastleSq; from = thisSide.QueenRookSq; Board[to] = Board[from]; // Move the piece Board[from] = emptyBoard[from]; // Replace from SquareInfo with the empty SquareInfo from emptyBoard Board[to].Location = to; // Update SqInfo location HashKey ^= pieceKeys[Board[to].Piece.ToInt(), from] ^ pieceKeys[Board[to].Piece.ToInt(), to]; break; } if (CapturedSqInfo.Piece.PieceColour != PieceColour.None) { CapturedSqInfo.Prev.Next = CapturedSqInfo.Next; // Delink the captured piece CapturedSqInfo.Next.Prev = CapturedSqInfo.Prev; pawnMoveOrCapture = true; // Clear enemy castling rights when capturing one of their rooks on its starting square if (to == otherSide.KingRookSq) CastleFlags = CastleFlags & ~(otherSide.CanCastleKS); if (to == otherSide.QueenRookSq) CastleFlags = CastleFlags & ~(otherSide.CanCastleQS); HashKey ^= pieceKeys[CapturedSqInfo.Piece.ToInt(), to]; } // Clear castle flag if king or rooks have moved if (Board[thisSide.KingStartSq].Piece == thisSide.King) { if (Board[thisSide.KingRookSq].Piece != thisSide.Rook) CastleFlags = CastleFlags & ~thisSide.CanCastleKS; if (Board[thisSide.QueenRookSq].Piece != thisSide.Rook) CastleFlags = CastleFlags & ~thisSide.CanCastleQS; } else CastleFlags = CastleFlags & ~(thisSide.CanCastleKS | thisSide.CanCastleQS); ToMove = toMove == PieceColour.White ? PieceColour.Black : PieceColour.White; HashKey ^= castleKeys[(int)move.OldCastleFlags] ^ castleKeys[(int)CastleFlags] ^ sideKey; move.CapturedSqInfo = CapturedSqInfo; move.HalfMovesSinceLastPawnMoveOrCapture = HalfMovesSinceLastPawnMoveOrCapture; undoStack.Push(move); if (pawnMoveOrCapture) HalfMovesSinceLastPawnMoveOrCapture = 0; else HalfMovesSinceLastPawnMoveOrCapture++; return; }
public bool MakeMove(ChessMove move) { // Make a move at Ply in the MoveHistory deleting all moves following // Look for the move with matching from and to squares in PossibleMoves and make that move since it has SpecialMoveType set up ChessMove foundMove = PossibleMoves.FirstOrDefault(o => o.FromSq == move.FromSq && o.ToSq == move.ToSq); if (foundMove == null) return false; // No matching move if (foundMove.Special == SpecialMoveType.Promotion) // If the match is a promotion, filter to the promoted piece if specified else a queen foundMove = PossibleMoves.FirstOrDefault(o => o.FromSq == move.FromSq && o.ToSq == move.ToSq && o.PromotedTo.PieceType == (move.PromotedTo.PieceType != PieceType.None ? move.PromotedTo.PieceType : PieceType.Queen)); while (MoveHistory.Count > undoStack.Count) MoveHistory.RemoveAt(MoveHistory.Count - 1); foundMove.GamePlyNr = CurrentGamePly; fillMoveText(foundMove); makeMove(foundMove); MoveHistory.Add(foundMove); generatePossibleMoves(PossibleMoves); removeIllegalMoves(PossibleMoves); if (isInCheck(thisSide, otherSide)) if (PossibleMoves.Count > 0) foundMove.Text += "+"; else foundMove.Text += "#"; return true; }
void fillMoveText(ChessMove move) { move.Text = ""; if (move.Special == SpecialMoveType.CastleKS) { move.Text = "O-O"; return; } if (move.Special == SpecialMoveType.CastleQS) { move.Text = "O-O-O"; return; } PieceType piece = Board[move.FromSq].Piece.PieceType; bool capture = (Board[move.ToSq].Piece.PieceType != PieceType.None || move.Special == SpecialMoveType.EnPassant); if (piece == PieceType.Pawn) { if (capture) move.Text += ((char)(move.FromSq.File + 'a')).ToString(); } else { // Can more than one of the move's PieceType move to the same square? int sameTo = 0, sameFile = 0, sameRank = 0; foreach (ChessMove m in PossibleMoves) { if (Board[m.FromSq].Piece.PieceType == piece) if (m.FromSq != move.FromSq && m.ToSq == move.ToSq) { sameTo++; if (m.FromSq.File == move.FromSq.File) sameFile++; // Another possible move with the same PieceType and From file moving to the same square if (m.FromSq.Rank == move.FromSq.Rank) sameRank++; // Likewise with rank } } move.Text = pieceStr[(int)piece].ToString(); if (sameTo > 0) { if (sameFile == 0 && sameRank == 0 || sameRank > 0) move.Text += ((char)(move.FromSq.File + 'a')).ToString(); // Needs rank specification to disambiguify if (sameFile > 0) move.Text += ((char)(move.FromSq.Rank + '1')).ToString(); // Needs file specificatino to disambiguify } } if (capture) move.Text += "x"; // Capture move.Text += move.ToSq.ToString(); if (move.Special == SpecialMoveType.Promotion) move.Text += "=" + pieceStr[(int)move.PromotedTo.PieceType].ToString(); // Promotion }
void addCaptureMove(ChessMove move) { move.Piece = Board[move.FromSq].Piece; // Adjust score according to most valuable victim least valuable attacker move.Score = captureScore + mvvLva[(int)Board[move.ToSq].Piece.PieceType, (int)move.Piece.PieceType]; tmpMoveList.Add(move); }
void addQuietMove(ChessMove move) { move.Piece = Board[move.FromSq].Piece; if (killers[0, CurrentGamePly].Piece == move.Piece && killers[0, CurrentGamePly].FromSq == move.FromSq && killers[0, CurrentGamePly].ToSq == move.ToSq) move.Score = killer0Score; else if (killers[1, CurrentGamePly].Piece == move.Piece && killers[1, CurrentGamePly].FromSq == move.FromSq && killers[1, CurrentGamePly].ToSq == move.ToSq) move.Score = killer1Score; else move.Score += searchHistory[move.Piece.ToInt(), move.ToSq]; tmpMoveList.Add(move); }
void movePiece(object o) { object[] args = (object[])o; ChessPiece piece = (ChessPiece)args[0]; int toFile = (int)args[1]; int toRank = (int)args[2]; if (toFile < 0 || toFile > 7 || toRank < 0 || toRank > 7 || (toFile == piece.File && toRank == piece.Rank)) return; ChessMove move = new ChessMove(new Square(piece.File, piece.Rank), new Square(toFile, toRank)); makeMove(move); }