public bool IsRepetition(int move) { if (!EngineConstants.EnableRepetitionTable) { return(false); } // if move was an attacking-move or pawn move, no repetition if (!MoveUtil.IsQuiet(move) || MoveUtil.GetSourcePieceIndex(move) == Pawn) { return(false); } var moveCountMin = Math.Max(0, MoveCounter - 50); for (var i = MoveCounter - 2; i >= moveCountMin; i -= 2) { if (ZobristKey != ZobristKeyHistory[i]) { continue; } if (Statistics.Enabled) { Statistics.Repetitions++; } return(true); } return(false); }
public static int GetSeeCaptureScore(ChessBoard cb, int move) { if (EngineConstants.Assert) { if (MoveUtil.GetAttackedPieceIndex(move) == 0) { Assert.IsTrue(MoveUtil.GetMoveType(move) != 0); } } var index = MoveUtil.GetToIndex(move); var allPieces = cb.AllPieces & ~Util.PowerLookup[MoveUtil.GetFromIndex(move)]; var slidingMask = MagicUtil.GetQueenMovesEmptyBoard(index) & allPieces; // add score when promotion if (MoveUtil.IsPromotion(move)) { return(EvalConstants.PromotionScore[MoveUtil.GetMoveType(move)] + EvalConstants.Material[MoveUtil.GetAttackedPieceIndex(move)] - GetSeeScore(cb, cb.ColorToMoveInverse, index, MoveUtil.GetMoveType(move), allPieces, slidingMask)); } return(EvalConstants.Material[MoveUtil.GetAttackedPieceIndex(move)] - GetSeeScore(cb, cb.ColorToMoveInverse, index, MoveUtil.GetSourcePieceIndex(move), allPieces, slidingMask)); }
public void AddCounterMove(int color, int parentMove, int counterMove) { if (EngineConstants.EnableCounterMoves) { _counterMoves[color][MoveUtil.GetSourcePieceIndex(parentMove)][MoveUtil.GetToIndex(parentMove)] = counterMove; } }
public void SetMvvlvaScores() { for (var j = _nextToMove[_ply]; j < _nextToGenerate[_ply]; j++) { _moveScores[j] = MoveUtil.GetAttackedPieceIndex(_moves[j]) * 6 - MoveUtil.GetSourcePieceIndex(_moves[j]); if (MoveUtil.GetMoveType(_moves[j]) == MoveUtil.TypePromotionQ) { _moveScores[j] += Queen * 6; } } }
private static bool MoveEquals(string moveString, MoveWrapper bestMove) { var move = bestMove.Move; var sourceIndex = MoveUtil.GetSourcePieceIndex(move); return(moveString.Length switch { 2 => sourceIndex == ChessConstants.Pawn && moveString.Substring(0, 1).Equals(bestMove.ToFile + "") && moveString.Substring(1, 1).Equals(bestMove.ToRank + ""), 3 when moveString.Substring(0, 1).ToLower().Equals(moveString.Substring(0, 1)) => sourceIndex == ChessConstants.Pawn && moveString.Substring(0, 1).Equals(bestMove.FromFile + "") && moveString.Substring(1, 1).Equals(bestMove.ToFile + "") && moveString.Substring(2, 1).Equals(bestMove.ToRank + ""), 3 => moveString.Substring(0, 1).Equals(ChessConstants.FenWhitePieces[sourceIndex]) && moveString.Substring(1, 1).Equals(bestMove.ToFile + "") && moveString.Substring(2, 1).Equals(bestMove.ToRank + ""), 4 => moveString.Substring(0, 1).Equals(ChessConstants.FenWhitePieces[sourceIndex]) && moveString.Substring(1, 1).Equals(bestMove.FromFile + "") && moveString.Substring(2, 1).Equals(bestMove.ToFile + "") && moveString.Substring(3, 1).Equals(bestMove.ToRank + ""), _ => throw new ArgumentException("Unknown move string: " + moveString) });
public int GetCounter(int color, int parentMove) { return(_counterMoves[color][MoveUtil.GetSourcePieceIndex(parentMove)][MoveUtil.GetToIndex(parentMove)]); }
public bool IsValidMove(int move) { // check piece at from square var fromIndex = MoveUtil.GetFromIndex(move); var fromSquare = Util.PowerLookup[fromIndex]; if ((Pieces[ColorToMove][MoveUtil.GetSourcePieceIndex(move)] & fromSquare) == 0) { return(false); } // check piece at to square var toIndex = MoveUtil.GetToIndex(move); var toSquare = Util.PowerLookup[toIndex]; var attackedPieceIndex = MoveUtil.GetAttackedPieceIndex(move); if (attackedPieceIndex == 0) { if (PieceIndexes[toIndex] != Empty) { return(false); } } else { if ((Pieces[ColorToMoveInverse][attackedPieceIndex] & toSquare) == 0 && !MoveUtil.IsEpMove(move)) { return(false); } } // check if move is possible switch (MoveUtil.GetSourcePieceIndex(move)) { case Pawn: if (MoveUtil.IsEpMove(move)) { return(toIndex == EpIndex && IsLegalEpMove(fromIndex)); } else { if (ColorToMove == White) { if (fromIndex > toIndex) { return(false); } // 2-move if (toIndex - fromIndex == 16 && (AllPieces & Util.PowerLookup[fromIndex + 8]) != 0) { return(false); } } else { if (fromIndex < toIndex) { return(false); } // 2-move if (fromIndex - toIndex == 16 && (AllPieces & Util.PowerLookup[fromIndex - 8]) != 0) { return(false); } } } break; case Knight: break; case Bishop: // fall-through case Rook: // fall-through case Queen: if ((InBetween[fromIndex][toIndex] & AllPieces) != 0) { return(false); } break; case King: if (!MoveUtil.IsCastlingMove(move)) { return(IsLegalKingMove(move)); } var castlingIndexes = CastlingUtil.GetCastlingIndexes(this); while (castlingIndexes != 0) { if (toIndex == BitOperations.TrailingZeroCount(castlingIndexes)) { return(CastlingUtil.IsValidCastlingMove(this, fromIndex, toIndex)); } castlingIndexes &= castlingIndexes - 1; } return(false); } if ((fromSquare & PinnedPieces) != 0) { if ((PinnedMovement[fromIndex][KingIndex[ColorToMove]] & toSquare) == 0) { return(false); } } if (CheckingPieces == 0) { return(true); } if (attackedPieceIndex == 0) { return(IsLegalNonKingMove(move)); } if (BitOperations.PopCount((ulong)CheckingPieces) == 2) { return(false); } return((toSquare & CheckingPieces) != 0); }
public bool IsLegal(int move) { return(MoveUtil.GetSourcePieceIndex(move) != King || IsLegalKingMove(move)); }
public void UndoMove(int move) { var fromIndex = MoveUtil.GetFromIndex(move); var toIndex = MoveUtil.GetToIndex(move); var toMask = 1L << toIndex; var fromToMask = (1L << fromIndex) ^ toMask; var sourcePieceIndex = MoveUtil.GetSourcePieceIndex(move); var attackedPieceIndex = MoveUtil.GetAttackedPieceIndex(move); PopHistoryValues(); // undo move Pieces[ColorToMoveInverse][All] ^= fromToMask; Pieces[ColorToMoveInverse][sourcePieceIndex] ^= fromToMask; PieceIndexes[fromIndex] = sourcePieceIndex; PsqtScore += EvalConstants.Psqt[sourcePieceIndex][ColorToMoveInverse][fromIndex] - EvalConstants.Psqt[sourcePieceIndex][ColorToMoveInverse][toIndex]; switch (sourcePieceIndex) { case Empty: // not necessary but provides a table-index break; case Pawn: PawnZobristKey ^= Zobrist.Piece[ColorToMoveInverse][Pawn][fromIndex]; if (MoveUtil.IsPromotion(move)) { Phase += EvalConstants.Phase[MoveUtil.GetMoveType(move)]; MaterialKey -= MaterialUtil.Values[ColorToMoveInverse][MoveUtil.GetMoveType(move)] - MaterialUtil.Values[ColorToMoveInverse][Pawn]; Pieces[ColorToMoveInverse][Pawn] ^= toMask; Pieces[ColorToMoveInverse][MoveUtil.GetMoveType(move)] ^= toMask; PsqtScore += EvalConstants.Psqt[Pawn][ColorToMoveInverse][toIndex] - EvalConstants.Psqt[MoveUtil.GetMoveType(move)][ColorToMoveInverse][toIndex]; } else { PawnZobristKey ^= Zobrist.Piece[ColorToMoveInverse][Pawn][toIndex]; } break; case King: if (MoveUtil.IsCastlingMove(move)) { CastlingUtil.UncastleRookUpdatePsqt(this, toIndex); } KingIndex[ColorToMoveInverse] = fromIndex; break; } // undo hit switch (attackedPieceIndex) { case Empty: break; case Pawn: if (MoveUtil.IsEpMove(move)) { PieceIndexes[toIndex] = Empty; toIndex += ColorFactor8[ColorToMove]; toMask = Util.PowerLookup[toIndex]; } PawnZobristKey ^= Zobrist.Piece[ColorToMove][Pawn][toIndex]; goto default; // fall-through default: PsqtScore += EvalConstants.Psqt[attackedPieceIndex][ColorToMove][toIndex]; Phase -= EvalConstants.Phase[attackedPieceIndex]; MaterialKey += MaterialUtil.Values[ColorToMove][attackedPieceIndex]; Pieces[ColorToMove][All] |= toMask; Pieces[ColorToMove][attackedPieceIndex] |= toMask; break; } PieceIndexes[toIndex] = attackedPieceIndex; AllPieces = Pieces[ColorToMove][All] | Pieces[ColorToMoveInverse][All]; EmptySpaces = ~AllPieces; ChangeSideToMove(); SetCheckingPinnedAndDiscoPieces(); if (EngineConstants.Assert) { ChessBoardTestUtil.TestValues(this); } }
public void DoMove(int move) { MoveCount++; var fromIndex = MoveUtil.GetFromIndex(move); var toIndex = MoveUtil.GetToIndex(move); var toMask = 1L << toIndex; var fromToMask = (1L << fromIndex) ^ toMask; var sourcePieceIndex = MoveUtil.GetSourcePieceIndex(move); var attackedPieceIndex = MoveUtil.GetAttackedPieceIndex(move); if (EngineConstants.Assert) { Assert.IsTrue(move != 0); Assert.IsTrue(attackedPieceIndex != King); Assert.IsTrue(attackedPieceIndex == 0 || (Util.PowerLookup[toIndex] & Pieces[ColorToMove][All]) == 0); Assert.IsTrue(IsValidMove(move)); } PushHistoryValues(); ZobristKey ^= Zobrist.Piece[ColorToMove][sourcePieceIndex][fromIndex] ^ Zobrist.Piece[ColorToMove][sourcePieceIndex][toIndex] ^ Zobrist.SideToMove; if (EpIndex != 0) { ZobristKey ^= Zobrist.EpIndex[EpIndex]; EpIndex = 0; } Pieces[ColorToMove][All] ^= fromToMask; Pieces[ColorToMove][sourcePieceIndex] ^= fromToMask; PieceIndexes[fromIndex] = Empty; PieceIndexes[toIndex] = sourcePieceIndex; PsqtScore += EvalConstants.Psqt[sourcePieceIndex][ColorToMove][toIndex] - EvalConstants.Psqt[sourcePieceIndex][ColorToMove][fromIndex]; switch (sourcePieceIndex) { case Pawn: PawnZobristKey ^= Zobrist.Piece[ColorToMove][Pawn][fromIndex]; if (MoveUtil.IsPromotion(move)) { Phase -= EvalConstants.Phase[MoveUtil.GetMoveType(move)]; MaterialKey += MaterialUtil.Values[ColorToMove][MoveUtil.GetMoveType(move)] - MaterialUtil.Values[ColorToMove][Pawn]; Pieces[ColorToMove][Pawn] ^= toMask; Pieces[ColorToMove][MoveUtil.GetMoveType(move)] |= toMask; PieceIndexes[toIndex] = MoveUtil.GetMoveType(move); ZobristKey ^= Zobrist.Piece[ColorToMove][Pawn][toIndex] ^ Zobrist.Piece[ColorToMove][MoveUtil.GetMoveType(move)][toIndex]; PsqtScore += EvalConstants.Psqt[MoveUtil.GetMoveType(move)][ColorToMove][toIndex] - EvalConstants.Psqt[Pawn][ColorToMove][toIndex]; } else { PawnZobristKey ^= Zobrist.Piece[ColorToMove][Pawn][toIndex]; // 2-move if (InBetween[fromIndex][toIndex] != 0) { if ((StaticMoves.PawnAttacks[ColorToMove][ BitOperations.TrailingZeroCount(InBetween[fromIndex][toIndex])] & Pieces[ColorToMoveInverse][Pawn]) != 0) { EpIndex = BitOperations.TrailingZeroCount(InBetween[fromIndex][toIndex]); ZobristKey ^= Zobrist.EpIndex[EpIndex]; } } } break; case Rook: if (CastlingRights != 0) { ZobristKey ^= Zobrist.Castling[CastlingRights]; CastlingRights = CastlingUtil.GetRookMovedOrAttackedCastlingRights(CastlingRights, fromIndex); ZobristKey ^= Zobrist.Castling[CastlingRights]; } break; case King: KingIndex[ColorToMove] = toIndex; if (CastlingRights != 0) { if (MoveUtil.IsCastlingMove(move)) { CastlingUtil.CastleRookUpdateKeyAndPsqt(this, toIndex); } ZobristKey ^= Zobrist.Castling[CastlingRights]; CastlingRights = CastlingUtil.GetKingMovedCastlingRights(CastlingRights, fromIndex); ZobristKey ^= Zobrist.Castling[CastlingRights]; } break; } // piece hit? switch (attackedPieceIndex) { case Empty: break; case Pawn: if (MoveUtil.IsEpMove(move)) { toIndex += ColorFactor8[ColorToMoveInverse]; toMask = Util.PowerLookup[toIndex]; PieceIndexes[toIndex] = Empty; } PawnZobristKey ^= Zobrist.Piece[ColorToMoveInverse][Pawn][toIndex]; PsqtScore -= EvalConstants.Psqt[Pawn][ColorToMoveInverse][toIndex]; Pieces[ColorToMoveInverse][All] ^= toMask; Pieces[ColorToMoveInverse][Pawn] ^= toMask; ZobristKey ^= Zobrist.Piece[ColorToMoveInverse][Pawn][toIndex]; MaterialKey -= MaterialUtil.Values[ColorToMoveInverse][Pawn]; break; case Rook: if (CastlingRights != 0) { ZobristKey ^= Zobrist.Castling[CastlingRights]; CastlingRights = CastlingUtil.GetRookMovedOrAttackedCastlingRights(CastlingRights, toIndex); ZobristKey ^= Zobrist.Castling[CastlingRights]; } goto default; // fall-through default: Phase += EvalConstants.Phase[attackedPieceIndex]; PsqtScore -= EvalConstants.Psqt[attackedPieceIndex][ColorToMoveInverse][toIndex]; Pieces[ColorToMoveInverse][All] ^= toMask; Pieces[ColorToMoveInverse][attackedPieceIndex] ^= toMask; ZobristKey ^= Zobrist.Piece[ColorToMoveInverse][attackedPieceIndex][toIndex]; MaterialKey -= MaterialUtil.Values[ColorToMoveInverse][attackedPieceIndex]; break; } AllPieces = Pieces[ColorToMove][All] | Pieces[ColorToMoveInverse][All]; EmptySpaces = ~AllPieces; ChangeSideToMove(); SetCheckingPinnedAndDiscoPieces(); if (EngineConstants.Assert) { ChessBoardTestUtil.TestValues(this); } }