/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if (Math.Abs(Board.File(from) - Board.File(to)) == Math.Abs(Board.Rank(from) - Board.Rank(to))) { return(board.IsPathClear(from, to)); } return(false); }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if (Board.File(from) != Board.File(to) && Board.Rank(from) != Board.Rank(to) && (Math.Abs(Board.File(from) - Board.File(to)) + Math.Abs(Board.Rank(from) - Board.Rank(to))) == 3) { return(true); } return(false); }
/// <summary> /// Updates if the board has a pawn that can be hit En-Passant after the move has been performed. /// </summary> /// <param name="afterState">The "BoardState" to update.</param> protected void SetEnPassentTarget(ref BoardState afterState) { if ((Board.Rank(m_from) == 1 && Board.Rank(m_to) == 3 && m_piece == Piece.WhitePawn) || (Board.Rank(m_from) == 6 && Board.Rank(m_to) == 4 && m_piece == Piece.BlackPawn)) { afterState.EnPassantTarget = m_to; } else { afterState.EnPassantTarget = Square.None; } }
/// <summary> /// Updates if the board has a pawn that can be hit En-Passant after the move has been performed. /// </summary> /// <param name="afterState">The "BoardState" to update.</param> private void SetEnPassentTarget(ref BoardState afterState) { if ((Board.Rank(From) == 1 && Board.Rank(To) == 3 && Piece == Piece.WhitePawn) || (Board.Rank(From) == 6 && Board.Rank(To) == 4 && Piece == Piece.BlackPawn)) { afterState.EnPassantTarget = To; } else { afterState.EnPassantTarget = Square.None; } }
/// <summary> /// XOR's an En-Passant target into the Zobrist key. /// </summary> public void HashFlipEnPassantTarget(Square square) { if (Board.Rank(square) == 3) { m_key ^= ZobristValues.Keys[1541 + Board.File(square)]; m_lock ^= ZobristValues.Locks[1541 + Board.File(square)]; } if (Board.Rank(square) == 4) { m_key ^= ZobristValues.Keys[1549 + Board.File(square)]; m_lock ^= ZobristValues.Locks[1549 + Board.File(square)]; } }
/// <summary> /// Verifies if a piece attacks a square. This method does not check if the piece on "from" /// on the board is of the same type as this FlyweightPiece represents. /// </summary> /// <param name="board">Board to check attacking on.</param> /// <param name="from">Square on which attacking piece is placed.</param> /// <param name="to">The square to check if attacked.</param> /// <returns>True if a FlyweightPiece placed on "from" square attacks the "to" square. False otherwise.</returns> public bool Attacks(Board board, Square from, Square to) { if ((m_color == PieceColor.White && Board.Rank(to) == Board.Rank(from) + 1) || (m_color == PieceColor.Black && Board.Rank(to) == Board.Rank(from) - 1)) { if ((Math.Abs(Board.File(to) - Board.File(from)) == 1) && (board.GetPieceColor(to) != m_color)) { return(true); } } return(false); }
/// <summary> /// Sets the hash value according to a board. /// </summary> /// <param name="board">The board a hash value will be generated for.</param> public void HashSet(Board board) { m_key = 0; m_lock = 0; if (board != null) { foreach (Square square in board) { if (board[square] != Piece.None) { m_key ^= ZobristValues.Keys[((int)board[square] * 128) + (int)square]; m_lock ^= ZobristValues.Locks[((int)board[square] * 128) + (int)square]; } } if (board.State.ColorToPlay == PieceColor.White) { m_key ^= ZobristValues.Keys[1536]; m_lock ^= ZobristValues.Locks[1536]; } if (board.State.WhiteCanCastleLong) { m_key ^= ZobristValues.Keys[1537]; m_lock ^= ZobristValues.Locks[1537]; } if (board.State.WhiteCanCastleShort) { m_key ^= ZobristValues.Keys[1538]; m_lock ^= ZobristValues.Locks[1538]; } if (board.State.BlackCanCastleLong) { m_key ^= ZobristValues.Keys[1539]; m_lock ^= ZobristValues.Locks[1539]; } if (board.State.BlackCanCastleShort) { m_key ^= ZobristValues.Keys[1540]; m_lock ^= ZobristValues.Locks[1540]; } if (board.State.EnPassantTarget != Square.None) { if (Board.Rank(board.State.EnPassantTarget) == 3) { m_key ^= ZobristValues.Keys[1541 + Board.File(board.State.EnPassantTarget)]; m_lock ^= ZobristValues.Locks[1541 + Board.File(board.State.EnPassantTarget)]; } if (Board.Rank(board.State.EnPassantTarget) == 4) { m_key ^= ZobristValues.Keys[1549 + Board.File(board.State.EnPassantTarget)]; m_lock ^= ZobristValues.Locks[1549 + Board.File(board.State.EnPassantTarget)]; } } } }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done in MoveOrganizer when adding a move. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { for (int i = 0; i < m_directions.Length; i++) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next()) { if (m_iterator.CurrentPiece() == Piece.None && (m_iterator.CurrentDirection() == Direction.Up || m_iterator.CurrentDirection() == Direction.Down)) { //Non hitting moves switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black non hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White non hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic non hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } if ((Board.Rank(m_iterator.CurrentSquare()) == 2 && m_iterator.CurrentDirection() == Direction.Up) || (Board.Rank(m_iterator.CurrentSquare()) == 5 && m_iterator.CurrentDirection() == Direction.Down)) { //Two squares forward opening move m_iterator.Next(); if (m_iterator.CurrentPiece() == Piece.None) { moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } } else if (m_iterator.CurrentPiece() != Piece.None && m_iterator.CurrentPieceColor() != m_color && m_iterator.CurrentDirection() != Direction.Up && m_iterator.CurrentDirection() != Direction.Down) { //Hitting moves switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White hitting promotion move moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new PawnPromotionMove(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } } } } //EnPassant moves if (board.State.EnPassantTarget != Square.None && Math.Abs(board.State.EnPassantTarget - location) == 1 && Board.Rank(board.State.EnPassantTarget) == Board.Rank(location)) { switch (m_color) { case PieceColor.White: moves.Add(new EnPassantCaptureMove(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) + 1))); break; case PieceColor.Black: moves.Add(new EnPassantCaptureMove(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) - 1))); break; } } } }
/// <summary> /// Moves the iterator to the next square. /// </summary> /// <returns>True if if the new square is a valid and existing square. False otherwise.</returns> public bool Next() { switch (m_direction) { case Direction.Up: if (Board.Rank(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1) { return(false); } m_currentSquare += 8; return(true); case Direction.UpRight: if (Board.Rank(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1 || Board.File(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1) { return(false); } m_currentSquare += 9; return(true); case Direction.Right: if (Board.File(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1) { return(false); } m_currentSquare += 1; return(true); case Direction.DownRight: if (Board.Rank(m_currentSquare) == 0 || Board.File(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1) { return(false); } m_currentSquare -= 7; return(true); case Direction.Down: if (Board.Rank(m_currentSquare) == 0) { return(false); } m_currentSquare -= 8; return(true); case Direction.DownLeft: if (Board.Rank(m_currentSquare) == 0 || Board.File(m_currentSquare) == 0) { return(false); } m_currentSquare -= 9; return(true); case Direction.Left: if (Board.File(m_currentSquare) == 0) { return(false); } m_currentSquare -= 1; return(true); case Direction.UpLeft: if (Board.Rank(m_currentSquare) == Board.NOF_SIDE_SQUARS - 1 || Board.File(m_currentSquare) == 0) { return(false); } m_currentSquare += 7; return(true); case Direction.NoDirection: default: return(false); } }
/// <summary> /// Generate moves a FlyweightPiece can make. /// This method does not varifies if a move puts its own king in check. /// This is done by a move when its carried out. /// </summary> /// <param name="board">Board to generate moves for.</param> /// <param name="location">Location of the piece.</param> /// <param name="moves">Container class to which all generated moves are added.</param> public void GenerateMoves(Board board, Square location, MoveOrganizer moves) { if (m_color == board.State.ColorToPlay) { //Non hitting moves m_iterator.Reset(board, location, m_directions[0]); if (m_iterator.Next()) { if (m_iterator.CurrentPiece() == Piece.None) { switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black non hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White non hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic non hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } //Two squares forward opening move if (Board.Rank(m_iterator.CurrentSquare()) == moveAgainRow) { m_iterator.Next(); if (m_iterator.CurrentPiece() == Piece.None) { moves.Add(new Move(board, location, m_iterator.CurrentSquare())); } } } } //Hitting moves to the left and right for (int i = 1; i < m_directions.Length; ++i) { m_iterator.Reset(board, location, m_directions[i]); if (m_iterator.Next()) { if (m_iterator.CurrentPieceColor() == m_opponentColor) { switch (Board.Rank(m_iterator.CurrentSquare())) { case 0: //Black hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.BlackRook)); break; case 7: //White hitting promotion move moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteBishop)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteKnight)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteQueen)); moves.Add(new Move(board, location, m_iterator.CurrentSquare(), Piece.WhiteRook)); break; default: //Basic hitting move moves.Add(new Move(board, location, m_iterator.CurrentSquare())); break; } } } } //EnPassant moves if (Math.Abs(board.State.EnPassantTarget - location) == 1) { switch (m_color) { case PieceColor.White: moves.Add(new Move(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) + 1), board.State.EnPassantTarget)); break; case PieceColor.Black: moves.Add(new Move(board, location, Board.Position(Board.File(board.State.EnPassantTarget), Board.Rank(location) - 1), board.State.EnPassantTarget)); break; } } } }