public virtual bool HasAnyValidMoves(Position from) { ChessUtilities.ThrowIfNull(from, "from"); ReadOnlyCollection <Move> validMoves = GetValidMoves(from, true); return(validMoves.Count > 0); }
GameStatus CalculateStatus(Player playerToValidate, bool validateHasAnyValidMoves) { if (_drawn) { return(new GameStatus(GameEvent.Draw, Player.None, _drawReason)); } if (_resigned != Player.None) { return(new GameStatus(GameEvent.Resign, _resigned, _resigned + " resigned")); } var other = ChessUtilities.GetOpponentOf(playerToValidate); if (IsInCheck(playerToValidate)) { if (validateHasAnyValidMoves && !HasAnyValidMoves(playerToValidate)) { return(new GameStatus(GameEvent.Checkmate, other, playerToValidate + " is checkmated")); } return(new GameStatus(GameEvent.Check, other, playerToValidate + " is in check")); } if (validateHasAnyValidMoves && !HasAnyValidMoves(playerToValidate)) { return(new GameStatus(GameEvent.Stalemate, other, "Stalemate")); } return(new GameStatus(GameEvent.None, Player.None, "No special event")); }
void UseGameCreationData(GameCreationData data) { Board = CloneBoard(data.Board); WhoseTurn = data.WhoseTurn; Piece e1 = GetPieceAt(File.E, 1); Piece e8 = GetPieceAt(File.E, 8); Piece a1 = GetPieceAt(File.A, 1); Piece h1 = GetPieceAt(File.H, 1); Piece a8 = GetPieceAt(File.A, 8); Piece h8 = GetPieceAt(File.H, 8); _whiteKingMoved |= (!(e1 is King) || e1.Owner != Player.White); _blackKingMoved |= (!(e8 is King) || e8.Owner != Player.Black); _whiteRookAMoved |= (!(a1 is Rook) || a1.Owner != Player.White || !data.CanWhiteCastleQueenSide); _whiteRookHMoved |= (!(h1 is Rook) || h1.Owner != Player.White || !data.CanWhiteCastleKingSide); _blackRookAMoved |= (!(a8 is Rook) || a8.Owner != Player.Black || !data.CanBlackCastleQueenSide); _blackRookHMoved |= (!(h8 is Rook) || h8.Owner != Player.Black || !data.CanBlackCastleKingSide); if (data.EnPassant != null) { var latestMove = new DetailedMove( new Move(new Square(data.EnPassant.File, data.WhoseTurn == Player.White ? 7 : 2), new Square(data.EnPassant.File, data.WhoseTurn == Player.White ? 5 : 4), ChessUtilities.GetOpponentOf(data.WhoseTurn)), new Pawn(ChessUtilities.GetOpponentOf(data.WhoseTurn)), false, CastlingType.None); _moves.Add(latestMove); } _halfMoveClock = data.HalfMoveClock; _fullMoveNumber = data.FullMoveNumber; }
public virtual bool WouldBeInCheckAfter(Move move, Player player) { ChessUtilities.ThrowIfNull(move, "move"); GameCreationData gcd = new GameCreationData(); gcd.Board = Board; gcd.CanWhiteCastleKingSide = CanWhiteCastleKingSide; gcd.CanWhiteCastleQueenSide = CanWhiteCastleQueenSide; gcd.CanBlackCastleKingSide = CanBlackCastleKingSide; gcd.CanBlackCastleQueenSide = CanBlackCastleQueenSide; gcd.EnPassant = null; if (_moves.Count > 0) { DetailedMove last = _moves.Last(); if (last.Piece is Pawn && new PositionDistance(last.OriginalPosition, last.NewPosition).DistanceY == 2) { gcd.EnPassant = new Position(last.NewPosition.File, last.Player == Player.White ? 3 : 6); } } gcd.HalfMoveClock = i_halfMoveClock; gcd.FullMoveNumber = i_fullMoveNumber; ChessGame copy = new ChessGame(gcd); Piece p = copy.GetPieceAt(move.OriginalPosition); copy.SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null); copy.SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, p); return(copy.IsInCheck(player)); }
public bool WouldBeInCheckAfter(Move move, Player player) { ChessUtilities.ThrowIfNull(move, nameof(move)); var gcd = new GameCreationData(); gcd.Board = Board; gcd.CanWhiteCastleKingSide = !_whiteRookHMoved && !_whiteKingMoved; gcd.CanWhiteCastleQueenSide = !_whiteRookAMoved && !_whiteKingMoved; gcd.CanBlackCastleKingSide = !_blackRookHMoved && !_blackKingMoved; gcd.CanBlackCastleQueenSide = !_blackRookAMoved && !_blackKingMoved; gcd.EnPassant = null; if (_moves.Count > 0) { var last = _moves.Last(); if (last.Piece is Pawn && new SquareDistance(last.OriginalPosition, last.NewPosition).DistanceY == 2) { gcd.EnPassant = new Square(last.NewPosition.File, last.Player == Player.White ? 3 : 6); } } gcd.HalfMoveClock = _halfMoveClock; gcd.FullMoveNumber = _fullMoveNumber; var copy = new ChessGame(gcd); copy.ApplyMove(move, true); var status = copy.CalculateStatus(player, false); return(status.Event == GameEvent.Check && status.PlayerWhoCausedEvent != player); }
ReadOnlyCollection <Move> GetValidMoves(Square from, bool returnIfAny) { ChessUtilities.ThrowIfNull(from, nameof(from)); var piece = GetPieceAt(from); return(piece == null || piece.Owner != WhoseTurn ? new ReadOnlyCollection <Move>(new List <Move>()) : piece.GetValidMoves(from, returnIfAny, this)); }
protected virtual ReadOnlyCollection <Move> GetValidMoves(Position from, bool returnIfAny) { ChessUtilities.ThrowIfNull(from, "from"); Piece piece = GetPieceAt(from); if (piece == null || piece.Owner != WhoseTurn) { return(new ReadOnlyCollection <Move>(new List <Move>())); } return(piece.GetValidMoves(from, returnIfAny, this, IsValidMove)); }
protected static Piece[][] CloneBoard(Piece[][] originalBoard) { ChessUtilities.ThrowIfNull(originalBoard, "originalBoard"); Piece[][] newBoard = new Piece[originalBoard.Length][]; for (int i = 0; i < originalBoard.Length; i++) { newBoard[i] = new Piece[originalBoard[i].Length]; Array.Copy(originalBoard[i], newBoard[i], originalBoard[i].Length); } return(newBoard); }
protected virtual void UseGameCreationData(GameCreationData data) { Board = CloneBoard(data.Board); WhoseTurn = data.WhoseTurn; Piece[] eighthRank = Board[0]; Piece[] firstRank = Board[7]; CanBlackCastleKingSide = CanBlackCastleQueenSide = CanWhiteCastleKingSide = CanWhiteCastleQueenSide = CastlingCanBeLegal; InitialWhiteKingFile = (File)Array.IndexOf(firstRank, new King(Player.White)); InitialBlackKingFile = (File)Array.IndexOf(eighthRank, new King(Player.Black)); if (CastlingCanBeLegal) { CanBlackCastleKingSide = data.CanBlackCastleKingSide; CanBlackCastleQueenSide = data.CanBlackCastleQueenSide; CanWhiteCastleKingSide = data.CanWhiteCastleKingSide; CanWhiteCastleQueenSide = data.CanWhiteCastleQueenSide; } InitialBlackRookFileQueensideCastling = CanBlackCastleQueenSide ? (File)Array.IndexOf(eighthRank, new Rook(Player.Black)) : File.None; InitialBlackRookFileKingsideCastling = CanBlackCastleKingSide ? (File)Array.LastIndexOf(eighthRank, new Rook(Player.Black)) : File.None; InitialWhiteRookFileQueensideCastling = CanWhiteCastleQueenSide ? (File)Array.IndexOf(firstRank, new Rook(Player.White)) : File.None; InitialWhiteRookFileKingsideCastling = CanWhiteCastleKingSide ? (File)Array.LastIndexOf(firstRank, new Rook(Player.White)) : File.None; if (InitialBlackRookFileQueensideCastling == File.None) { CanBlackCastleQueenSide = false; } if (InitialBlackRookFileKingsideCastling == File.None) { CanBlackCastleKingSide = false; } if (InitialWhiteRookFileKingsideCastling == File.None) { CanWhiteCastleKingSide = false; } if (InitialWhiteRookFileQueensideCastling == File.None) { CanWhiteCastleQueenSide = false; } if (data.EnPassant != null) { DetailedMove latestMove = new DetailedMove(new Move(new Position(data.EnPassant.File, data.WhoseTurn == Player.White ? 7 : 2), new Position(data.EnPassant.File, data.WhoseTurn == Player.White ? 5 : 4), ChessUtilities.GetOpponentOf(data.WhoseTurn)), new Pawn(ChessUtilities.GetOpponentOf(data.WhoseTurn)), false, CastlingType.None); _moves.Add(latestMove); } i_halfMoveClock = data.HalfMoveClock; i_fullMoveNumber = data.FullMoveNumber; }
protected virtual bool IsValidMove(Move move, bool validateCheck, bool careAboutWhoseTurnItIs) { ChessUtilities.ThrowIfNull(move, "move"); if (move.OriginalPosition.Equals(move.NewPosition)) { return(false); } Piece piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); if (careAboutWhoseTurnItIs && move.Player != WhoseTurn) { return(false); } if (piece == null || piece.Owner != move.Player) { return(false); } Piece pieceAtDestination = GetPieceAt(move.NewPosition); bool isCastle = pieceAtDestination is Rook && piece is King && pieceAtDestination.Owner == piece.Owner; if (pieceAtDestination != null && pieceAtDestination.Owner == move.Player && !isCastle) { return(false); } if (!piece.IsValidMove(move, this)) { return(false); } if (validateCheck) { if (!isCastle && WouldBeInCheckAfter(move, move.Player)) { return(false); } } return(true); }
bool IsValidMove(Move move, bool validateCheck, bool careAboutWhoseTurnItIs) // this is the weirdest bool ever. why wouldn't you care? { ChessUtilities.ThrowIfNull(move, nameof(move)); if (move.OriginalPosition.Equals(move.NewPosition)) { return(false); } var piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); if (careAboutWhoseTurnItIs && move.Player != WhoseTurn) { return(false); } if (piece.Owner != move.Player) { return(false); } var pieceAtDestination = GetPieceAt(move.NewPosition); if (pieceAtDestination != null && pieceAtDestination.Owner == move.Player) { return(false); } if (!piece.IsValidMove(move, this)) { return(false); } if (validateCheck && WouldBeInCheckAfter(move, move.Player)) { return(false); } return(true); }
public virtual MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured) { ChessUtilities.ThrowIfNull(move, "move"); captured = null; if (!alreadyValidated && !IsValidMove(move)) { return(MoveType.Invalid); } MoveType type = MoveType.Move; Piece movingPiece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); Piece capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank); captured = capturedPiece; Piece newPiece = movingPiece; bool isCapture = capturedPiece != null; CastlingType castle = CastlingType.None; if (movingPiece is Pawn) { i_halfMoveClock = 0; PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition); if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null) { // en passant isCapture = true; captured = GetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank); SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null); } if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1)) { newPiece = MapPgnCharToPiece(move.Promotion.Value, move.Player).AsPromotion(); type |= MoveType.Promotion; } } else if (movingPiece is King) { if (movingPiece.Owner == Player.White) { CanWhiteCastleKingSide = CanWhiteCastleQueenSide = false; } else { CanBlackCastleKingSide = CanBlackCastleQueenSide = false; } if (CastlingCanBeLegal && ((GetPieceAt(move.NewPosition) is Rook && GetPieceAt(move.NewPosition).Owner == move.Player) || ((move.NewPosition.File == File.C || move.NewPosition.File == File.G) && (move.Player == Player.White ? InitialWhiteKingFile : InitialBlackKingFile) == File.E && move.OriginalPosition.File == File.E))) { castle = ApplyCastle(move); type |= MoveType.Castling; isCapture = false; } } else if (movingPiece is Rook) { if (move.Player == Player.White) { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1) { CanWhiteCastleQueenSide = false; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1) { CanWhiteCastleKingSide = false; } } else { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8) { CanBlackCastleQueenSide = false; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8) { CanBlackCastleKingSide = false; } } } if (isCapture) { type |= MoveType.Capture; i_halfMoveClock = 0; if (move.NewPosition.File == File.A && move.NewPosition.Rank == 1) { CanWhiteCastleQueenSide = false; } else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 1) { CanWhiteCastleKingSide = false; } else if (move.NewPosition.File == File.A && move.NewPosition.Rank == 8) { CanBlackCastleQueenSide = false; } else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 8) { CanBlackCastleKingSide = false; } } if (!isCapture && !(movingPiece is Pawn)) { i_halfMoveClock++; if (i_halfMoveClock >= 100) { fiftyMoves = true; } else { fiftyMoves = false; } } if (move.Player == Player.Black) { i_fullMoveNumber++; } if (castle == CastlingType.None) { SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece); SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null); } WhoseTurn = ChessUtilities.GetOpponentOf(move.Player); AddDetailedMove(new DetailedMove(move, movingPiece, isCapture, castle)); return(type); }
protected bool IsValidMove(Move move, bool validateCheck) { ChessUtilities.ThrowIfNull(move, "move"); return(IsValidMove(move, validateCheck, true)); }
public bool IsValidMove(Move move) { ChessUtilities.ThrowIfNull(move, "move"); return(IsValidMove(move, true, true)); }
public Piece GetPieceAt(Position position) { ChessUtilities.ThrowIfNull(position, "position"); return(GetPieceAt(position.File, position.Rank)); }
public MoveType ApplyMove(Move move, bool alreadyValidated) { ChessUtilities.ThrowIfNull(move, nameof(move)); if (!alreadyValidated && !IsValidMove(move)) { return(MoveType.Invalid); } var type = MoveType.Move; var movingPiece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); var capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank); var newPiece = movingPiece; var isCapture = capturedPiece != null; var castle = CastlingType.None; if (movingPiece is Pawn) { _halfMoveClock = 0; var pd = new SquareDistance(move.OriginalPosition, move.NewPosition); if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null) { // en passant isCapture = true; SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null); } if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1)) { newPiece = move.Promotion; type |= MoveType.Promotion; } } else if (movingPiece is King) { if (movingPiece.Owner == Player.White) { _whiteKingMoved = true; } else { _blackKingMoved = true; } if (new SquareDistance(move.OriginalPosition, move.NewPosition).DistanceX == 2) { castle = ApplyCastle(move); type |= MoveType.Castling; } } else if (movingPiece is Rook) { if (move.Player == Player.White) { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1) { _whiteRookAMoved = true; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1) { _whiteRookHMoved = true; } } else { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8) { _blackRookAMoved = true; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8) { _blackRookHMoved = true; } } } if (isCapture) { type |= MoveType.Capture; _halfMoveClock = 0; } if (!isCapture && !(movingPiece is Pawn)) { _halfMoveClock++; canClaimDraw = _halfMoveClock == 100; // ahaa so THAT's the HalfMove clock .. number of Plys } if (move.Player == Player.Black) { _fullMoveNumber++; } SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece); SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null); WhoseTurn = ChessUtilities.GetOpponentOf(move.Player); _moves.Add(new DetailedMove(move, movingPiece, isCapture, castle)); return(type); }
public virtual bool IsWinner(Player player) { return(IsCheckmated(ChessUtilities.GetOpponentOf(player))); }
public Piece GetPieceAt(Square position) { ChessUtilities.ThrowIfNull(position, nameof(position)); return(GetPieceAt(position.File, position.Rank)); }
public bool HasAnyValidMoves(Square from) { ChessUtilities.ThrowIfNull(from, nameof(from)); return(GetValidMoves(from, true).Count > 0); }
bool IsValidMove(Move move, bool validateCheck) { ChessUtilities.ThrowIfNull(move, nameof(move)); return(IsValidMove(move, validateCheck, true)); }
public ReadOnlyCollection <Move> GetValidMoves(Square from) { ChessUtilities.ThrowIfNull(from, nameof(from)); return(GetValidMoves(from, false)); }
public ReadOnlyCollection <Move> GetValidMoves(Position from) { ChessUtilities.ThrowIfNull(from, "from"); return(GetValidMoves(from, false)); }
protected virtual string GetSanForMove(Move move, Piece movingPiece, bool isCapture, CastlingType castle, List <Position> ambiguities) { if (castle == CastlingType.KingSide) { return("O-O"); } if (castle == CastlingType.QueenSide) { return("O-O-O"); } bool needsUnambigFile = false; bool needsUnambigRank = false; if (ambiguities.Count > 0) { foreach (Position amb in ambiguities) { if (amb.Rank == move.OriginalPosition.Rank) { needsUnambigFile = true; } if (amb.File == move.OriginalPosition.File) { needsUnambigRank = true; } } if (!needsUnambigFile && !needsUnambigRank) { needsUnambigFile = true; } } StringBuilder sanBuilder = new StringBuilder(); if (!(movingPiece is Pawn)) { sanBuilder.Append(char.ToUpperInvariant(movingPiece.GetFenCharacter())); } else if (isCapture) { sanBuilder.Append(move.OriginalPosition.File.ToString().ToLowerInvariant()); needsUnambigFile = false; needsUnambigRank = false; } if (needsUnambigFile) { sanBuilder.Append(move.OriginalPosition.File.ToString().ToLowerInvariant()); } if (needsUnambigRank) { sanBuilder.Append(move.OriginalPosition.Rank.ToString()); } if (isCapture) { sanBuilder.Append("x"); } sanBuilder.Append(move.NewPosition.ToString().ToLowerInvariant()); if (move.Promotion.HasValue) { sanBuilder.Append("="); sanBuilder.Append(move.Promotion.Value); } if (IsWinner(ChessUtilities.GetOpponentOf(WhoseTurn))) { sanBuilder.Append("#"); } else if (IsInCheck(WhoseTurn)) { sanBuilder.Append("+"); } return(sanBuilder.ToString()); }
public virtual MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured) { ChessUtilities.ThrowIfNull(move, "move"); captured = null; if (!alreadyValidated && !IsValidMove(move)) { return(MoveType.Invalid); } MoveType type = MoveType.Move; Piece movingPiece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); Piece capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank); captured = capturedPiece; Piece newPiece = movingPiece; enp = "-1"; bool isCapture = capturedPiece != null; CastlingType castle = CastlingType.None; if (movingPiece is Pawn) { i_halfMoveClock = 0; PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition); if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null) { // en passant isCapture = true; captured = GetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank); enp = move.NewPosition.File.ToString().ToLower() + move.OriginalPosition.Rank.ToString(); SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null); } if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1)) { //get promotion type char PromoteTo; if (move.Promotion == null) { string promote; Console.Write("enter promotion type:"); promote = Console.ReadLine(); switch (promote) { case "queen": PromoteTo = 'Q'; break; case "bishop": PromoteTo = 'B'; break; case "knight": PromoteTo = 'N'; break; case "rook": PromoteTo = 'R'; break; default: PromoteTo = 'Q'; break; } } else { PromoteTo = 'Q'; } newPiece = MapPgnCharToPiece(PromoteTo, move.Player).AsPromotion(); type |= MoveType.Promotion; } } else if (movingPiece is King) { if (movingPiece.Owner == Player.White) { CanWhiteCastleKingSide = CanWhiteCastleQueenSide = false; } else { CanBlackCastleKingSide = CanBlackCastleQueenSide = false; } if (CastlingCanBeLegal && ((GetPieceAt(move.NewPosition) is Rook && GetPieceAt(move.NewPosition).Owner == move.Player) || ((move.NewPosition.File == File.C || move.NewPosition.File == File.G) && (move.Player == Player.White ? InitialWhiteKingFile : InitialBlackKingFile) == File.E && move.OriginalPosition.File == File.E))) { castle = ApplyCastle(move); type |= MoveType.Castling; isCapture = false; } } else if (movingPiece is Rook) { if (move.Player == Player.White) { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1) { CanWhiteCastleQueenSide = false; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1) { CanWhiteCastleKingSide = false; } } else { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8) { CanBlackCastleQueenSide = false; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8) { CanBlackCastleKingSide = false; } } } if (isCapture) { type |= MoveType.Capture; i_halfMoveClock = 0; if (move.NewPosition.File == File.A && move.NewPosition.Rank == 1) { CanWhiteCastleQueenSide = false; } else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 1) { CanWhiteCastleKingSide = false; } else if (move.NewPosition.File == File.A && move.NewPosition.Rank == 8) { CanBlackCastleQueenSide = false; } else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 8) { CanBlackCastleKingSide = false; } } if (!isCapture && !(movingPiece is Pawn)) { i_halfMoveClock++; if (i_halfMoveClock >= 100) { fiftyMoves = true; } else { fiftyMoves = false; } } if (move.Player == Player.Black) { i_fullMoveNumber++; } if (castle == CastlingType.None) { SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece); SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null); } WhoseTurn = ChessUtilities.GetOpponentOf(move.Player); AddDetailedMove(new DetailedMove(move, movingPiece, isCapture, castle)); return(type); }