protected override void ComputeMoves() { // Compute universal moves for rooks this.moves = new Dictionary <Position, Bitboard>(); int column, row; for (column = Position.min; column <= Position.max; column++) { for (row = Position.min; row <= Position.max; row++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); int positionRow, positionColumn; for (positionColumn = Position.min; positionColumn <= Position.max; positionColumn++) { if (positionColumn != column) { positionBitboard.FlipPosition(new Position(positionColumn, row)); } } for (positionRow = Position.min; positionRow <= Position.max; positionRow++) { if (positionRow != row) { positionBitboard.FlipPosition(new Position(column, positionRow)); } } this.moves[position] = positionBitboard; } } }
protected override Bitboard AdditionalMoveProcessing(Bitboard movesForCurrentPosition) { if (this.side == Side.Black) { movesForCurrentPosition = movesForCurrentPosition.ComputeRayIntersections(this.chessBoard.GetPieceLocations(Side.White), this.GetCurrentPosition(), true); } else { movesForCurrentPosition = movesForCurrentPosition.ComputeRayIntersections(this.chessBoard.GetPieceLocations(Side.Black), this.GetCurrentPosition(), true); } movesForCurrentPosition = movesForCurrentPosition.ComputeRayIntersections(this.chessBoard.GetPieceLocations(this.side), this.GetCurrentPosition(), false); // The current moving side check is needed since we don't want to compute castling as a move when we're trying to see if the king is checked // Castling if (this.chessBoard.CurrentMovingSide() == this.side && this.canCastle && !this.chessBoard.IsKingInCheck(this.side) ) { // King side castling if (this.chessBoard.GetPieceAtPosition(new Position(1, this.GetCurrentPosition().GetRow())) != null && this.chessBoard.GetPieceAtPosition(new Position(1, this.GetCurrentPosition().GetRow())).GetType().Name == Constants.PieceClassNames.Rook) { Rook kingSideRook = (Rook)this.chessBoard.GetPieceAtPosition(new Position(1, this.GetCurrentPosition().GetRow())); // If both move positions are unoccupied if (kingSideRook.canCastle && this.chessBoard.GetPieceAtPosition(new Position(2, this.GetCurrentPosition().GetRow())) == null && this.chessBoard.GetPieceAtPosition(new Position(3, this.GetCurrentPosition().GetRow())) == null ) { // The final move will be filtered if the King's target position leaves it in check, so the last check here should be the intermediate position, or where the Rook will be after the move if (this.IsMoveSafe(new Position(3, this.GetCurrentPosition().GetRow()))) { movesForCurrentPosition.FlipPosition(new Position(2, this.GetCurrentPosition().GetRow())); } } } // Queen side castling if (this.chessBoard.GetPieceAtPosition(new Position(8, this.GetCurrentPosition().GetRow())) != null && this.chessBoard.GetPieceAtPosition(new Position(8, this.GetCurrentPosition().GetRow())).GetType().Name == Constants.PieceClassNames.Rook) { Rook queenSideRook = (Rook)this.chessBoard.GetPieceAtPosition(new Position(8, this.GetCurrentPosition().GetRow())); if (queenSideRook.canCastle && this.chessBoard.GetPieceAtPosition(new Position(5, this.GetCurrentPosition().GetRow())) == null && this.chessBoard.GetPieceAtPosition(new Position(6, this.GetCurrentPosition().GetRow())) == null ) { // The final move will be filtered if the King's target position leaves it in check, so the last check here should be the intermediate position, or where the Rook will be after the move if (this.IsMoveSafe(new Position(5, this.GetCurrentPosition().GetRow()))) { movesForCurrentPosition.FlipPosition(new Position(6, this.GetCurrentPosition().GetRow())); } } } } return(movesForCurrentPosition); }
protected override void ComputeMoves() { // Compute moves based on side for pawns this.moves = new Dictionary <Position, Bitboard>(); int row, column; if (this.side == Side.Black) { // Starting position row = 7; for (column = Position.min; column <= Position.max; column++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); positionBitboard.FlipPosition(new Position(column, row - 1)); positionBitboard.FlipPosition(new Position(column, row - 2)); this.moves[position] = positionBitboard; } // All other forward positions (till pawn promotion) for (row = 6; row >= 2; row--) { for (column = Position.min; column <= Position.max; column++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); positionBitboard.FlipPosition(new Position(column, row - 1)); this.moves[position] = positionBitboard; } } } else { // Starting position row = 2; for (column = Position.min; column <= Position.max; column++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); positionBitboard.FlipPosition(new Position(column, row + 1)); positionBitboard.FlipPosition(new Position(column, row + 2)); this.moves[position] = positionBitboard; } // All other forward positions (till pawn promotion) for (row = 3; row <= 7; row++) { for (column = Position.min; column <= Position.max; column++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); positionBitboard.FlipPosition(new Position(column, row + 1)); this.moves[position] = positionBitboard; } } } }
protected override void ComputeMoves() { // Compute universal moves for bishops this.moves = new Dictionary <Position, Bitboard>(); int column, row; for (column = Position.min; column <= Position.max; column++) { for (row = Position.min; row <= Position.max; row++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); int positionRow, positionColumn; for (positionColumn = column + 1; positionColumn <= Position.max; positionColumn++) { positionRow = row + (positionColumn - column); if (positionRow <= Position.max) { positionBitboard.FlipPosition(new Position(positionColumn, positionRow)); } positionRow = row - (positionColumn - column); if (positionRow >= Position.min) { positionBitboard.FlipPosition(new Position(positionColumn, positionRow)); } } for (positionColumn = column - 1; positionColumn >= Position.min; positionColumn--) { positionRow = row + (column - positionColumn); if (positionRow <= Position.max) { positionBitboard.FlipPosition(new Position(positionColumn, positionRow)); } positionRow = row - (column - positionColumn); if (positionRow >= Position.min) { positionBitboard.FlipPosition(new Position(positionColumn, positionRow)); } } this.moves[position] = positionBitboard; } } }
public Bitboard ComputeRayIntersections(Bitboard bitboardToIntersect, Position movingPiecePosition, bool includeIntersectionPosition) { // Recompute this bitboard after stopping all rays from the moving piece that are intersecting the passed bitboard Bitboard newBitboard = new Bitboard(); // Compute a bitboard containing all intersection points Bitboard intersectBitboard = this.ComplementBitboard(this.IntersectBitboard(bitboardToIntersect)); int row; for (row = 0; row < this.bitboard.Length; row++) { newBitboard.GetBitboard()[row] = (byte)this.GetBitboard()[row]; intersectBitboard.GetBitboard()[row] = (byte)(intersectBitboard.GetBitboard()[row] & newBitboard.GetBitboard()[row]); } // Now, for each intersect position, go along the unit vector connecting the moving position to this position and wipe out all points till the edge of the bitboard // These "vectors" can only be horizontal, vertical or diagonal foreach (Position intersectionPosition in intersectBitboard.GetPositions()) { Vector2 positionVector = new Vector2(intersectionPosition.GetColumn() - movingPiecePosition.GetColumn(), intersectionPosition.GetRow() - movingPiecePosition.GetRow()); if (positionVector.x > 1 || positionVector.x < -1) { positionVector.x = positionVector.x / Mathf.Abs(positionVector.x); } if (positionVector.y > 1 || positionVector.y < -1) { positionVector.y = positionVector.y / Mathf.Abs(positionVector.y); } Position clearPosition = new Position(intersectionPosition.GetColumn(), intersectionPosition.GetRow()); if (includeIntersectionPosition) { // Don't process the intersection position clearPosition.SetColumn(clearPosition.GetColumn() + (int)positionVector.x); clearPosition.SetRow(clearPosition.GetRow() + (int)positionVector.y); } while (clearPosition.GetColumn() >= Position.min && clearPosition.GetColumn() <= Position.max && clearPosition.GetRow() >= Position.min && clearPosition.GetRow() <= Position.max) { if (newBitboard.ValueAtPosition(clearPosition) > 0) { newBitboard.FlipPosition(clearPosition); } else { break; } clearPosition.SetColumn(clearPosition.GetColumn() + (int)positionVector.x); clearPosition.SetRow(clearPosition.GetRow() + (int)positionVector.y); } } return(newBitboard); }
public Bitboard GetSafeMovesForCurrentPosition() { Bitboard availableMoves = this.GetMovesForCurrentPosition(); foreach (Position position in availableMoves.GetPositions()) { if (!IsMoveSafe(position)) { availableMoves.FlipPosition(position); } } return(availableMoves); }
protected override void ComputeMoves() { // Compute universal moves for knights this.moves = new Dictionary <Position, Bitboard>(); int column, row; for (column = Position.min; column <= Position.max; column++) { for (row = Position.min; row <= Position.max; row++) { Position position = new Position(column, row); Bitboard positionBitboard = new Bitboard(); List <Position> knightPositions = new List <Position>(); knightPositions.Add(new Position(column + 2, row + 1)); knightPositions.Add(new Position(column + 2, row - 1)); knightPositions.Add(new Position(column - 2, row + 1)); knightPositions.Add(new Position(column - 2, row - 1)); knightPositions.Add(new Position(column + 1, row + 2)); knightPositions.Add(new Position(column + 1, row - 2)); knightPositions.Add(new Position(column - 1, row + 2)); knightPositions.Add(new Position(column - 1, row - 2)); foreach (Position knightPosition in knightPositions) { if (knightPosition.GetColumn() >= Position.min && knightPosition.GetColumn() <= Position.max && knightPosition.GetRow() >= Position.min && knightPosition.GetRow() <= Position.max) { positionBitboard.FlipPosition(knightPosition); } } this.moves[position] = positionBitboard; } } }
protected override Bitboard AdditionalMoveProcessing(Bitboard movesForCurrentPosition) { // For pawns, extra moves would constitute: // 1. Normal attack // 2. En passant // Normal attack // Check the row ahead for opponent locations int rowToCheck; Side sideToCheck; if (this.side == Side.Black) { rowToCheck = this.GetCurrentPosition().GetRow() - 1; sideToCheck = Side.White; } else { rowToCheck = this.GetCurrentPosition().GetRow() + 1; sideToCheck = Side.Black; } Bitboard friendlyLocations = this.chessBoard.GetPieceLocations(this.side); Bitboard opponentLocations = this.chessBoard.GetPieceLocations(sideToCheck); // First, remove any moves that go through friendly or opponent movesForCurrentPosition = movesForCurrentPosition.ComputeRayIntersections(friendlyLocations, this.GetCurrentPosition(), false); movesForCurrentPosition = movesForCurrentPosition.ComputeRayIntersections(opponentLocations, this.GetCurrentPosition(), false); if (this.GetCurrentPosition().GetColumn() > Position.min) { if (opponentLocations.ValueAtPosition(new Position(this.GetCurrentPosition().GetColumn() - 1, rowToCheck)) > 0) { movesForCurrentPosition.FlipPosition(new Position(this.GetCurrentPosition().GetColumn() - 1, rowToCheck)); } } if (this.GetCurrentPosition().GetColumn() < Position.max) { if (opponentLocations.ValueAtPosition(new Position(this.GetCurrentPosition().GetColumn() + 1, rowToCheck)) > 0) { movesForCurrentPosition.FlipPosition(new Position(this.GetCurrentPosition().GetColumn() + 1, rowToCheck)); } } // En passant rowToCheck = this.GetCurrentPosition().GetRow(); if (this.GetCurrentPosition().GetColumn() > Position.min) { if (opponentLocations.ValueAtPosition(new Position(this.GetCurrentPosition().GetColumn() - 1, rowToCheck)) > 0) { // Also check if the piece at this location is a pawn which has just performed a double jump AbstractPiece passedPiece = this.chessBoard.GetPieceAtPosition(new Position(this.GetCurrentPosition().GetColumn() - 1, rowToCheck)); if (passedPiece != null && passedPiece.GetType().Name.CompareTo(this.GetType().Name) == 0 && ((Pawn)passedPiece).allowEnPassantCapture) { int attackPoint = rowToCheck; if (this.side == Side.Black) { attackPoint--; } else { attackPoint++; } movesForCurrentPosition.FlipPosition(new Position(this.GetCurrentPosition().GetColumn() - 1, attackPoint)); } } } if (this.GetCurrentPosition().GetColumn() < Position.max) { if (opponentLocations.ValueAtPosition(new Position(this.GetCurrentPosition().GetColumn() + 1, rowToCheck)) > 0) { AbstractPiece passedPiece = this.chessBoard.GetPieceAtPosition(new Position(this.GetCurrentPosition().GetColumn() + 1, rowToCheck)); if (passedPiece != null && passedPiece.GetType().Name.CompareTo(this.GetType().Name) == 0 && ((Pawn)passedPiece).allowEnPassantCapture) { int attackPoint = rowToCheck; if (this.side == Side.Black) { attackPoint--; } else { attackPoint++; } movesForCurrentPosition.FlipPosition(new Position(this.GetCurrentPosition().GetColumn() + 1, attackPoint)); } } } return(movesForCurrentPosition); }