public void ZobristUpdateTest_DisableCastling() { Move move = new Move(gameState, BitboardUtils.GetBitboard(6), BitboardUtils.GetBitboard(7), PieceType.King); ulong expectedHash = GetPieceBitstring(0, PieceType.King, 6) ^ GetPieceBitstring(0, PieceType.King, 7) ^ GetBlackTurnBitstring(); TestMove("r4k2/1p4pp/pb6/3N2B1/4Q1b1/P4N2/1pn2PPP/4RRK1 w - - 2 12", move, expectedHash); move = new Move(gameState, BitboardUtils.GetBitboard(4), BitboardUtils.GetBitboard(13), PieceType.King); expectedHash = GetPieceBitstring(0, PieceType.King, 4) ^ GetPieceBitstring(0, PieceType.King, 13) ^ GetPieceBitstring(1, PieceType.Knight, 13) ^ GetCastlingBitstring()[0, 0] ^ GetCastlingBitstring()[0, 1] ^ GetBlackTurnBitstring(); TestMove("rnbqkb1r/pp1p1ppp/2p5/4P3/2B5/8/PPP1NnPP/RNBQK2R w KQkq - 0 1", move, expectedHash); move = new CastlingMove(gameState, BitboardUtils.GetBitboard(60), BitboardUtils.GetBitboard(58)); expectedHash = GetPieceBitstring(1, PieceType.King, 60) ^ GetPieceBitstring(1, PieceType.King, 58) ^ GetPieceBitstring(1, PieceType.Rook, 56) ^ GetPieceBitstring(1, PieceType.Rook, 59) ^ GetCastlingBitstring()[1, 0] ^ GetBlackTurnBitstring(); TestMove("r3kbr1/pp3ppp/n1p5/3pP1q1/2B2Nb1/2N1B3/PPPQ1KPP/4R2R b q - 5 6", move, expectedHash); move = new Move(gameState, BitboardUtils.GetBitboard(7), BitboardUtils.GetBitboard(6), PieceType.Rook); expectedHash = GetPieceBitstring(0, PieceType.Rook, 7) ^ GetPieceBitstring(0, PieceType.Rook, 6) ^ GetCastlingBitstring()[0, 1] ^ GetBlackTurnBitstring(); TestMove("rnbqkb1r/pp1p1ppp/2p5/4P3/2B5/8/PPP1NnPP/RNBQK2R w KQkq - 0 1", move, expectedHash); move = new Move(gameState, BitboardUtils.GetBitboard(13), BitboardUtils.GetBitboard(7), PieceType.Knight); expectedHash = GetPieceBitstring(1, PieceType.Knight, 13) ^ GetPieceBitstring(1, PieceType.Knight, 7) ^ GetPieceBitstring(0, PieceType.Rook, 7) ^ GetCastlingBitstring()[0, 1] ^ GetBlackTurnBitstring(); TestMove("rnbqkb1r/pp1p1ppp/2p5/4P3/2B5/2N5/PPP1NnPP/R1BQK2R b KQkq - 1 1", move, expectedHash); }
/// <summary> /// Generates the move. /// </summary> /// <param name="board">The board</param> /// <param name="from">The starting square</param> /// <param name="to">The ending square</param> /// <returns></returns> internal override Move GenerateMove(Board board, int from, int to) { Move move; // if it's a castling move // CanCastleLong already verifies if the king will // end in check so we don't have to verify it again if (CanCastleLong(board, from, to)) { move = new CastlingMove(board.Status, Board.E8, Board.C8, new Move(board.Status, Board.A8, Board.D8, this), this); move.ChangeSideToMove(); // change side to move move.MakeBlackLongCastlingUnavail(); // reset castling availability move.MakeBlackShortCastlingUnavail(); // reset castling availability move.SetEnPassantTarget(null); // reset en passant target move.IncrementPly(); // increment the ply move.IncrementMoves(); // the number of moves is incremented after Black moves return(move); } // if it's a castling move // CanCastleShort already verifies if the king will // end in check so we don't have to verify it again if (CanCastleShort(board, from, to)) { move = new CastlingMove(board.Status, Board.E8, Board.G8, new Move(board.Status, Board.H8, Board.F8, this), this); move.ChangeSideToMove(); // change side to move move.MakeBlackLongCastlingUnavail(); // reset castling availability move.MakeBlackShortCastlingUnavail(); // reset castling availability move.SetEnPassantTarget(null); // reset en passant target move.IncrementPly(); // increment the ply move.IncrementMoves(); // the number of moves is incremented after Black moves return(move); } // if it's a regular move // just reset castling availability move = base.GenerateMove(board, from, to); if (move != null) { move.MakeBlackLongCastlingUnavail(); move.MakeBlackShortCastlingUnavail(); return(move); } else { return(null); } }
protected IEnumerable <Move> GenerateCastlingMoves(ulong sq) { IrrevState irrevState = gameState.GetIrrevState(); for (int i = 0; i <= 1; i++) { if (IsCastlingAllowed(irrevState, i)) { ulong target = castlingKingTarget[i] & BitboardUtils.FIRST_RANK[gameState.Turn]; Move move = new CastlingMove(gameState, sq, target); yield return(move); } } }
/// <summary> /// Запуск анимации перемещения фигуры. Ход фигуры на BoardState выполняется после завершения анимации. /// </summary> /// <param name="move"></param> public void BeginMove(FigureMove move) { // Блокируем интерфейс interfaceLocked = true; // Убираем выделение PieceController.ClearSelection(); // Убираем все красные линии foreach (GameObject redLine in redLines) { Destroy(redLine); } redLines.Clear(); // Находим GameObject фигуры Transform piece = FindTransformByPos(move.from); // Перемещаем спрайт на слой выше SpriteRenderer spriteRenderer = piece.GetChild(0).GetComponent <SpriteRenderer>(); spriteRenderer.sortingLayerName = "CurrentPiece"; currentMovingPiece = piece; // Запускаем анимацию MoveAnimation moveAnimation = piece.GetComponent <MoveAnimation>(); currentMove = move; moveAnimation.StartAnimation( beginPos: new Vector3(move.from.x, move.from.y), endPos: new Vector3(move.to.x, move.to.y), finishedCallback: EndMove ); // При рокировке запускаем анимацию для ладьи if (move.GetType() == typeof(CastlingMove)) { // Находим GameObject ладьи CastlingMove castlingMove = (CastlingMove)move; Transform rook = FindTransformByPos(castlingMove.rookFrom); // Запускаем анимацию MoveAnimation rookMoveAnimation = rook.GetComponent <MoveAnimation>(); rookMoveAnimation.StartAnimation( beginPos: new Vector3(castlingMove.rookFrom.x, castlingMove.rookFrom.y), endPos: new Vector3(castlingMove.rookTo.x, castlingMove.rookTo.y), finishedCallback: null ); } }
public void ZobristUpdateTest_Castling() { Move move = new CastlingMove(gameState, BitboardUtils.GetBitboard(4), BitboardUtils.GetBitboard(6)); ulong expectedHash = GetPieceBitstring(0, PieceType.Rook, 7) ^ GetPieceBitstring(0, PieceType.Rook, 5) ^ GetPieceBitstring(0, PieceType.King, 4) ^ GetPieceBitstring(0, PieceType.King, 6) ^ GetCastlingBitstring()[0, 0] ^ GetCastlingBitstring()[0, 1] ^ GetBlackTurnBitstring(); TestMove("r1bqkbnr/ppp2ppp/2n5/3pp3/4P3/3B1N2/PPPP1PPP/RNBQK2R w KQkq - 0 4", move, expectedHash); move = new CastlingMove(gameState, BitboardUtils.GetBitboard(60), BitboardUtils.GetBitboard(58)); expectedHash = GetPieceBitstring(1, PieceType.Rook, 56) ^ GetPieceBitstring(1, PieceType.Rook, 59) ^ GetPieceBitstring(1, PieceType.King, 60) ^ GetPieceBitstring(1, PieceType.King, 58) ^ GetCastlingBitstring()[1, 0] ^ GetCastlingBitstring()[1, 1] ^ GetBlackTurnBitstring(); TestMove("r3kbnr/ppp2ppp/2nq4/3pp3/4P1b1/3B1N2/PPPPQPPP/RNBR2K1 b kq - 5 6", move, expectedHash); }
// *** INITIALIZATION *** // #region Initialize public override void Initialize(Game game) { base.Initialize(game); castlingMoves = new CastlingMove[game.NumPlayers, MAX_CASTLING_MOVES]; nCastlingMoves = new int[game.NumPlayers]; searchStackPrivs = new int[Game.MAX_PLY]; gameHistoryPrivs = new int[Game.MAX_GAME_LENGTH]; allPrivsPerPlayer = new int[game.NumPlayers]; allPrivString = ""; nextPriv = 1; privEraseMap = new int[game.Board.NumSquaresExtended]; // Hook up MoveBeingPlayed event handler game.MoveBeingPlayed += MoveBeingPlayedHandler; }
/// <summary> /// Двигает короля в другую клетку. /// </summary> public override void ExecuteMove(FigureMove move) { if (move.GetType() == typeof(CastlingMove)) { CastlingMove castlingMove = (CastlingMove)move; // Ищем ладью Figure rook = boardState.GetFigureAtCell(castlingMove.rookFrom); if (rook == null || rook.GetType() != typeof(Rook)) { throw new InvalidOperationException("Не найдена ладья для рокировки"); } // Двигаем ладью MoveFigure(rook, castlingMove.rookTo, takeFigure: false); } // Вызов базового метода Move base.ExecuteMove(move); }
/// <summary> /// Calculates castling moves. /// </summary> /// <param name="opt">The generator parameters.</param> public static void CalculateCastling(GeneratorParameters opt) { var kingLSB = CastlingConstants.InitialKingBitboard; var leftRookLSB = CastlingConstants.InitialLeftRookBitboard; var rightRookLSB = CastlingConstants.InitialRightRookBitboard; var shortMoveArea = CastlingConstants.ShortCastlingMoveArea; var shortCheckArea = CastlingConstants.ShortCastlingCheckArea; var longMoveArea = CastlingConstants.LongCastlingMoveArea; var longCheckArea = CastlingConstants.LongCastlingCheckArea; var kingPosition = InitialKingPosition; if (opt.FriendlyColor == Color.Black) { kingLSB <<= 56; leftRookLSB <<= 56; rightRookLSB <<= 56; shortMoveArea <<= 56; shortCheckArea <<= 56; longMoveArea <<= 56; longCheckArea <<= 56; kingPosition += new Position(0, 7); } if (IsCastlingPossible(CastlingType.Short, opt) && IsKingOnPosition(kingLSB, opt) && IsRookOnPosition(rightRookLSB, opt) && IsCastlingAreaEmpty(shortMoveArea, opt.OccupancySummary) && !IsCastlingAreaChecked(opt.EnemyColor, shortCheckArea, opt)) { var kingDestinationPosition = kingPosition + new Position(2, 0); var move = new CastlingMove(kingPosition, kingDestinationPosition, PieceType.King, opt.FriendlyColor, CastlingType.Short); opt.Bitboard.Moves.AddLast(move); } if (IsCastlingPossible(CastlingType.Long, opt) && IsKingOnPosition(kingLSB, opt) && IsRookOnPosition(leftRookLSB, opt) && IsCastlingAreaEmpty(longMoveArea, opt.OccupancySummary) && !IsCastlingAreaChecked(opt.EnemyColor, longCheckArea, opt)) { var kingDestinationPosition = kingPosition - new Position(2, 0); var move = new CastlingMove(kingPosition, kingDestinationPosition, PieceType.King, opt.FriendlyColor, CastlingType.Long); opt.Bitboard.Moves.AddLast(move); } }
// *** OPERATIONS *** // #region AddCastlingMove public void AddCastlingMove(int player, int kingfrom, int kingto, int otherfrom, int otherto, char privChar) { int priv = 0; if (privLookup.ContainsKey(privChar)) { priv = privLookup[privChar]; } else { priv = nextPriv; nextPriv = nextPriv << 1; privLookup.Add(privChar, priv); } if (allPrivString.IndexOf(privChar) < 0) { allPrivString += privChar; } allPrivsPerPlayer[player] |= priv; castlingMoves[player, nCastlingMoves[player]++] = new CastlingMove(kingfrom, kingto, otherfrom, otherto, priv, privChar); }