internal ChessMove[] GetBoardThreats(out bool ownKingUnderThreat, PiecePlayer playerToEvaluate) { ChessBoardLocation kingLocation = new ChessBoardLocation(-1, -1); List <ChessMove> opponentMoves = new List <ChessMove>(); var player = playerToEvaluate == PiecePlayer.White ? PiecePlayer.Black : PiecePlayer.White; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (_pieces[i, j].Player == playerToEvaluate) { var moves = GetAvailableMoves(playerToEvaluate, i, j, false); opponentMoves.AddRange(moves); } else if (_pieces[i, j].Player == player && _pieces[i, j].Rank == PieceRank.King) { kingLocation = new ChessBoardLocation(i, j); } } } ownKingUnderThreat = opponentMoves.Where(o => o.To.HorizontalLocation == kingLocation.HorizontalLocation && o.To.VerticalLocation == kingLocation.VerticalLocation).Any(); if (ownKingUnderThreat == true) { // Currently board has been verified as "check". // Now let's verify that is it also "checkmate". } return(opponentMoves.ToArray()); }
public ChessMove(PieceRank rank, PiecePlayer player, int horizontalLocationFrom, int verticalLocationFrom, int horizontalLocationTo, int verticalLocationTo, ChessSpecialMove specialMove) { Rank = rank; Player = player; From = new ChessBoardLocation(horizontalLocationFrom, verticalLocationFrom); To = new ChessBoardLocation(horizontalLocationTo, verticalLocationTo); SpecialMove = specialMove; }
private bool IsOccupiedByOpponent(PiecePlayer player, int column, int row) { if (column < 0 || column > BOARD_SIZE - 1 || row < 0 || row > BOARD_SIZE - 1) { // Out of bounds return(false); } return(_pieces[column, row].Player != player && _pieces[column, row].Player != PiecePlayer.None); }
internal void SetBoard(string board) { CleanUp(); string[] rows = board.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < rows.Length; i++) { for (int j = 0; j < rows[i].Length; j++) { char piece = rows[i][j]; PiecePlayer pieceColor = char.ToLower(piece) == piece ? PiecePlayer.Black : PiecePlayer.White; PieceRank pieceRank; switch (char.ToLower(piece)) { case '-': pieceColor = PiecePlayer.None; pieceRank = PieceRank.None; break; case 'k': pieceRank = PieceRank.King; break; case 'q': pieceRank = PieceRank.Queen; break; case 'b': pieceRank = PieceRank.Bishop; break; case 'r': pieceRank = PieceRank.Rook; break; case 'p': pieceRank = PieceRank.Pawn; break; case 'n': pieceRank = PieceRank.Knight; break; default: throw new ArgumentOutOfRangeException("board"); } _pieces[j, i] = new ChessBoardPiece(pieceColor, pieceRank); } } }
private void GetKnightMove(PiecePlayer player, List <ChessMove> moves, int column, int row) { moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column - 1, row + 2)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column - 1, row - 2)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column + 1, row + 2)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column + 1, row - 2)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column - 2, row + 1)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column - 2, row - 1)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column + 2, row + 1)); moves.Add(new ChessMove(PieceRank.Knight, player, column, row, column + 2, row - 1)); }
private void GetPawnMovesEnPassant(PiecePlayer player, List <ChessMove> moves, int column, int row, int columnDelta, int rowDelta) { // En passant move: if (_previousMove != null && IsOccupiedByOpponent(player, column + columnDelta, row) == true) { ChessBoardPiece piece = GetPiece(column + columnDelta, row); if (piece.Rank == PieceRank.Pawn && piece.Player != player) { if (_previousMove.To.HorizontalLocation == column + columnDelta && _previousMove.To.VerticalLocation == row && Math.Abs(_previousMove.To.VerticalLocation - _previousMove.From.VerticalLocation) == 2) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column + columnDelta, row + rowDelta, ChessSpecialMove.EnPassant)); } } } }
private void GetKingMove(PiecePlayer player, List <ChessMove> moves, int column, int row, bool validateCheck) { moves.Add(new ChessMove(PieceRank.King, player, column, row, column - 1, row - 1)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column, row - 1)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column - 1, row)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column + 1, row + 1)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column, row + 1)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column + 1, row)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column + 1, row - 1)); moves.Add(new ChessMove(PieceRank.King, player, column, row, column - 1, row + 1)); // Check castling moves (rules from Wikipedia: http://en.wikipedia.org/wiki/Chess) // - Neither of the pieces involved in castling may have been previously // moved during the game. // - There must be no pieces between the king and the rook. // - The king may not be in check, nor may the king pass through squares // that are under attack by enemy pieces, nor move to a square where it is in check. int kingStartColumn = 4; int kingStartRow = player == PiecePlayer.White ? 7 : 0; if (column == kingStartColumn && row == kingStartRow) { // King is at start location. Has it moved earlier? var kingsEarlierMove = _moves.Where( m => m.First().Player == player && m.First().Rank == PieceRank.King).FirstOrDefault(); if (kingsEarlierMove != null) { // King has already moved so castling is not anymore available return; } // Left hand side rook GetKingCastlingMove(player, moves, column, row, 0, validateCheck); // Right hand side rook GetKingCastlingMove(player, moves, column, row, 7, validateCheck); } }
private void GetHorizontalAndVerticalMoves(PieceRank rank, PiecePlayer player, List <ChessMove> moves, int column, int row) { // To left for (int i = column - 1; i >= 0; i--) { if (IsOccupiedByOpponent(player, i, row) == true) { moves.Add(new ChessMove(rank, player, column, row, i, row)); } else if (IsEmpty(i, row) == true) { moves.Add(new ChessMove(rank, player, column, row, i, row)); continue; } break; } // To right for (int i = column + 1; i < BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, i, row) == true) { moves.Add(new ChessMove(rank, player, column, row, i, row)); } else if (IsEmpty(i, row) == true) { moves.Add(new ChessMove(rank, player, column, row, i, row)); continue; } break; } // To up for (int i = row - 1; i >= 0; i--) { if (IsOccupiedByOpponent(player, column, i) == true) { moves.Add(new ChessMove(rank, player, column, row, column, i)); } else if (IsEmpty(column, i) == true) { moves.Add(new ChessMove(rank, player, column, row, column, i)); continue; } break; } // To down for (int i = row + 1; i < BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, column, i) == true) { moves.Add(new ChessMove(rank, player, column, row, column, i)); } else if (IsEmpty(column, i) == true) { moves.Add(new ChessMove(rank, player, column, row, column, i)); continue; } break; } }
private void GetDiagonalMoves(PieceRank rank, PiecePlayer player, List <ChessMove> moves, int column, int row) { // To north-east for (int i = 1; i <= BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, column + i, row - i) == true) { moves.Add(new ChessMove(rank, player, column, row, column + i, row - i)); } else if (IsEmpty(column + i, row - i) == true) { moves.Add(new ChessMove(rank, player, column, row, column + i, row - i)); continue; } break; } // To south-east for (int i = 1; i <= BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, column + i, row + i) == true) { moves.Add(new ChessMove(rank, player, column, row, column + i, row + i)); } else if (IsEmpty(column + i, row + i) == true) { moves.Add(new ChessMove(rank, player, column, row, column + i, row + i)); continue; } break; } // To north-west for (int i = 1; i <= BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, column - i, row - i) == true) { moves.Add(new ChessMove(rank, player, column, row, column - i, row - i)); } else if (IsEmpty(column - i, row - i) == true) { moves.Add(new ChessMove(rank, player, column, row, column - i, row - i)); continue; } break; } // To south-west for (int i = 1; i <= BOARD_SIZE; i++) { if (IsOccupiedByOpponent(player, column - i, row + i) == true) { moves.Add(new ChessMove(rank, player, column, row, column - i, row + i)); } else if (IsEmpty(column - i, row + i) == true) { moves.Add(new ChessMove(rank, player, column, row, column - i, row + i)); continue; } break; } }
private void GetQueenMove(PiecePlayer player, List <ChessMove> moves, int column, int row) { GetHorizontalAndVerticalMoves(PieceRank.Queen, player, moves, column, row); GetDiagonalMoves(PieceRank.Queen, player, moves, column, row); }
private void GetBishopMove(PiecePlayer player, List <ChessMove> moves, int column, int row) { GetDiagonalMoves(PieceRank.Bishop, player, moves, column, row); }
private void GetRookMove(PiecePlayer player, List <ChessMove> moves, int column, int row) { GetHorizontalAndVerticalMoves(PieceRank.Rook, player, moves, column, row); }
private void GetPawnMoves(PiecePlayer player, List <ChessMove> moves, int column, int row) { ChessSpecialMove specialMove = ChessSpecialMove.None; if (player == PiecePlayer.White) { if (row == 1) { specialMove = ChessSpecialMove.Promotion; } if (IsOccupiedByOpponent(player, column, row - 1) == false) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column, row - 1, specialMove)); } if (row == 6 && IsEmpty(column, row - 1) == true && IsEmpty(column, row - 2) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column, row - 2)); } // Move only available for pawn if there is opponent piece: if (IsOccupiedByOpponent(player, column + 1, row - 1) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column + 1, row - 1, specialMove)); } if (IsOccupiedByOpponent(player, column - 1, row - 1) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column - 1, row - 1, specialMove)); } GetPawnMovesEnPassant(player, moves, column, row, -1, -1); GetPawnMovesEnPassant(player, moves, column, row, 1, -1); } else { if (row == 6) { specialMove = ChessSpecialMove.Promotion; } if (IsOccupiedByOpponent(player, column, row + 1) == false) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column, row + 1, specialMove)); } if (row == 1 && IsEmpty(column, row + 1) == true && IsEmpty(column, row + 2) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column, row + 2)); } // Move only available for pawn if there is opponent piece: if (IsOccupiedByOpponent(player, column + 1, row + 1) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column + 1, row + 1, specialMove)); } if (IsOccupiedByOpponent(player, column - 1, row + 1) == true) { moves.Add(new ChessMove(PieceRank.Pawn, player, column, row, column - 1, row + 1, specialMove)); } GetPawnMovesEnPassant(player, moves, column, row, -1, 1); GetPawnMovesEnPassant(player, moves, column, row, 1, 1); } }
private void GetKingCastlingMove(PiecePlayer player, List <ChessMove> moves, int column, int row, int rookColumn, bool validateCheck) { var rookPosition = _pieces[rookColumn, row]; if (rookPosition.Player != player || rookPosition.Rank != PieceRank.Rook) { // Not current players rook return; } var rookRow = player == PiecePlayer.White ? 1 : 8; // Rook is at start location. Has it moved earlier? var rooksEarlierMove = _moves.Where( m => m.First().Player == player && m.First().Rank == PieceRank.Rook && m.First().From.VerticalLocation == rookRow && m.First().From.HorizontalLocation == rookColumn).FirstOrDefault(); if (rooksEarlierMove != null) { // Rook has already moved so castling is not anymore available return; } bool ownKingUnderThreat = false; ChessMove[] opponentMoves = new ChessMove[0]; if (validateCheck == true) { opponentMoves = GetBoardThreats( out ownKingUnderThreat, CurrentPlayer == PiecePlayer.White ? PiecePlayer.Black : PiecePlayer.White); } if (ownKingUnderThreat == false) { // Set defaults to left hand side rook castling int delta = -2; int startColumn = 2; int endColumn = column; if (rookColumn > endColumn) { delta = 2; startColumn = column + 1; endColumn = rookColumn; } for (int currentColumn = startColumn; currentColumn < endColumn; currentColumn++) { if (_pieces[currentColumn, row].Player != PiecePlayer.None) { return; } ChessMove opponentMove = opponentMoves.Where( o => o.To.HorizontalLocation == currentColumn && o.To.VerticalLocation == row).FirstOrDefault(); if (opponentMove != null) { return; } } // This castling move is valid moves.Add(new ChessMove(PieceRank.King, player, column, row, column + delta, row, ChessSpecialMove.Castling)); } }
private ChessMove[] GetAvailableMoves(PiecePlayer player, int column, int row, bool validateCheck) { List <ChessMove> moves = new List <ChessMove>(); if (player == PiecePlayer.None) { // Game over already return(moves.ToArray()); } if (_pieces[column, row].Player == player) { switch (_pieces[column, row].Rank) { case PieceRank.Pawn: GetPawnMoves(player, moves, column, row); break; case PieceRank.Knight: GetKnightMove(player, moves, column, row); break; case PieceRank.Bishop: GetBishopMove(player, moves, column, row); break; case PieceRank.Rook: GetRookMove(player, moves, column, row); break; case PieceRank.Queen: GetQueenMove(player, moves, column, row); break; case PieceRank.King: GetKingMove(player, moves, column, row, validateCheck); break; default: break; } // Validate all moves for (int i = moves.Count - 1; i >= 0; i--) { bool invalidMove = false; ChessMove move = moves[i]; if (move.To.HorizontalLocation < 0 || move.To.HorizontalLocation > BOARD_SIZE - 1) { // Out of bounds invalidMove = true; } else if (move.To.VerticalLocation < 0 || move.To.VerticalLocation > BOARD_SIZE - 1) { // Out of bounds invalidMove = true; } else if (_pieces[move.To.HorizontalLocation, move.To.VerticalLocation].Player == player) { // Already occupied by team mate invalidMove = true; } if (invalidMove == false && validateCheck == true) { // Let's see if this move would cause check MakeMove(move, false); GetBoardThreats(out var ownKingUnderThreat); if (ownKingUnderThreat == true) { invalidMove = true; } Undo(); } if (invalidMove == true) { moves.RemoveAt(i); } } } return(moves.ToArray()); }
public ChessBoardPiece(PiecePlayer player, PieceRank rank) { Player = player; Rank = rank; }