static void Main(string[] args) { // Let's start by creating a chess game instance. ChessGame game = new ChessGame(); // Now the game's board is in the start position and it's white's turn. Console.WriteLine("It's this color's turn: {0}", game.WhoseTurn); // This is how to find out which piece is at a certain position: Piece pieceAtA1 = game.GetPieceAt(new Position("A1")); // Or "a1", the casing doesn't matter /* There are other overloading options as well: * game.GetPieceAt(new Position(File.A, 1)); * game.GetPieceAt(File.A, 1); * All those three options return the same. */ Console.WriteLine("What piece is there at A1? {0}", pieceAtA1.GetFenCharacter()); // GetFenCharacter() returns the FEN character for the given piece. White piece: uppercase, black piece: lowercase. The character is the first char of a piece's name (exception: Knight -> N/n because King -> K/k). // The Piece class is the abstract base class for pieces. All piece classes (e.g. Rook) derive from this class. // White has to make a turn. They want to move their E2 pawn to E4. Is that valid? Move e2e4 = new Move("E2", "E4", Player.White); bool isValid = game.IsValidMove(e2e4); Console.WriteLine("E2-E4 for white is valid: {0}", isValid); // Great, it's valid! So white wants to actually make that move. MoveType type = game.ApplyMove(e2e4, true); // The first argument is the move, the second argument indicates whether it's already validated. Here it is, so pass 'true'. If it's not validated yet, ApplyMove will do it. **Only pass `true` if it's really validated! If you pass `true`, ApplyMove won't do ANY validity checks.** // The return type is the MoveType enum. It holds one, or a combination, of these values: Invalid, Move, Capture, Castling, Promotion // Each valid move will always carry the 'Move' value. If it's also something else, it will carry both values (e.g. if the move is a capture, `type` will have the value MoveType.Move | MoveType.Capture). // MoveType is a flags enumeration. https://msdn.microsoft.com/en-us/library/ms229062%28v=vs.100%29.aspx // e4 is just a normal move, so `type` will just be MoveType.Move. Console.WriteLine("Move type: {0}", type); // When a move has been made, check the Status property. It will let you know if there is a special event: check, checkmate, stalemate ... GameStatus status = game.Status; Console.WriteLine("Special event? {0}", status.Event); // Here it just returns 'None' because nothing special happened. // GameStatus has two other properties: PlayerWhoCausedEvent (quite self-explanatory) and EventExplanation (used if Chess.NET needs to be more specific about an event, e.g. when it's a draw, explaining why). // Now it's black's turn. Console.WriteLine("It's this color's turn: {0}", game.WhoseTurn); // You can figure out all valid moves using GetValidMoves. IEnumerable<Move> validMoves = game.GetValidMoves(Player.Black); // Here it returns all valid moves for black, but you can also find all valid moves *from a certain position* by passing a Position instance as argument. Console.WriteLine("How many valid moves does black have? {0}", validMoves.Count()); // It might happen that you don't really care about all valid moves, but just want to know if there are valid moves. Chess.NET also has a method for that: bool hasValidMoves = game.HasAnyValidMoves(Player.Black); // Again, you can also pass a Position instance here. Console.WriteLine("Black has any valid moves: {0}", hasValidMoves); // Congratulations! You have learned about the most important methods of Chess.NET. Enjoy using the library :) Console.ReadKey(); }
public void CantMoveIfNotTurn() { // arrange var game = GetInitiatedGame(); game.Start(player1Id); var move = new ChessDotNet.Move("e7", "e5", Player.Black); // act var moveWasSuccessful = game.Move(player2Id, move); Assert.False(moveWasSuccessful.WasSuccessful, "Player was able to move despite not being their turn"); }
public void CanMove() { // arrange var game = GetInitiatedGame(); game.Start(player1Id); var move = new ChessDotNet.Move("e2", "e4", Player.White); // act var moveWasSuccessful = game.Move(player1Id, move); // assert Assert.True(moveWasSuccessful.WasSuccessful, "Failed to move despite all conditions being fine"); }
public void CantMoveTwiceInARow() { // arrange var game = GetInitiatedGame(); game.Start(player1Id); var move1 = new ChessDotNet.Move("e2", "e4", Player.White); var move2 = new ChessDotNet.Move("f2", "f4", Player.White); // act var move1Result = game.Move(player1Id, move1); var move2Result = game.Move(player1Id, move2); Assert.True(move1Result.WasSuccessful, "Player was unable to move despite it being their turn"); Assert.False(move2Result.WasSuccessful, "Player moved despite it not being their turn"); }
protected virtual ReadOnlyCollection<Move> GetValidMovesBishop(Position from, bool returnIfAny) { Utilities.ThrowIfNull(from, "from"); List<Move> validMoves = new List<Move>(); ChessPiece cp = GetPieceAt(from); int l0 = Board.Length; int l1 = Board[0].Length; for (int i = -7; i < 8; i++) { if (i == 0) continue; if ((int)from.Rank + i > -1 && (int)from.Rank + i < l0 && (int)from.File + i > -1 && (int)from.File + i < l1) { Move move = new Move(from, new Position(from.File + i, from.Rank + i), cp.Player); if (IsValidMove(move)) { validMoves.Add(move); if (returnIfAny) return new ReadOnlyCollection<Move>(validMoves); } } if ((int)from.Rank - i > -1 && (int)from.Rank - i < l0 && (int)from.File + i > -1 && (int)from.File + i < l1) { Move move = new Move(from, new Position(from.File + i, from.Rank - i), cp.Player); if (IsValidMove(move)) { validMoves.Add(move); if (returnIfAny) return new ReadOnlyCollection<Move>(validMoves); } } } return new ReadOnlyCollection<Move>(validMoves); }
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); 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; }
protected virtual bool IsValidMove(Move move, bool validateCheck) { Utilities.ThrowIfNull(move, "move"); if (move.OriginalPosition.Equals(move.NewPosition)) return false; ChessPiece piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); if (move.Player != WhoseTurn) return false; if (piece.Player != move.Player) return false; if (GetPieceAt(move.NewPosition).Player == move.Player) { return false; } switch (piece.Piece) { case Piece.King: if (!IsValidMoveKing(move)) return false; break; case Piece.Pawn: if (!IsValidMovePawn(move)) return false; break; case Piece.Queen: if (!IsValidMoveQueen(move)) return false; break; case Piece.Rook: if (!IsValidMoveRook(move)) return false; break; case Piece.Bishop: if (!IsValidMoveBishop(move)) return false; break; case Piece.Knight: if (!IsValidMoveKnight(move)) return false; break; default: return false; } if (validateCheck && WouldBeInCheckAfter(move, move.Player)) { return false; } return true; }
protected virtual bool ApplyMove(Move move, bool alreadyValidated, bool validateHasAnyValidMoves) { Utilities.ThrowIfNull(move, "move"); if (!alreadyValidated && !IsValidMove(move)) return false; ChessPiece movingPiece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); ChessPiece newPiece = movingPiece; if (movingPiece.Piece == Piece.Pawn) { PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition); if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition).Piece == Piece.None) { // en passant SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, ChessPiece.None); } if (move.NewPosition.Rank == (move.Player == Player.White ? Rank.Eight : Rank.One)) { newPiece = new ChessPiece(move.Promotion, move.Player); } } else if (movingPiece.Piece == Piece.King) { if (movingPiece.Player == Player.White) _whiteKingMoved = true; else _blackKingMoved = true; if (new PositionDistance(move.OriginalPosition, move.NewPosition).DistanceX == 2) { Rank rank = move.Player == Player.White ? Rank.One : Rank.Eight; File rookFile = move.NewPosition.File == File.C ? File.A : File.H; File newRookFile = move.NewPosition.File == File.C ? File.D : File.F; SetPieceAt(newRookFile, rank, new ChessPiece(Piece.Rook, move.Player)); SetPieceAt(rookFile, rank, ChessPiece.None); } } else if (movingPiece.Piece == Piece.Rook) { if (move.Player == Player.White) { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == Rank.One) _whiteRookAMoved = true; else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == Rank.One) _whiteRookHMoved = true; } else { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == Rank.Eight) _blackRookAMoved = true; else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == Rank.Eight) _blackRookHMoved = true; } } SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece); SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, ChessPiece.None); WhoseTurn = Utilities.GetOpponentOf(move.Player); _moves.Add(move); return true; }
public abstract bool IsValidMove(Move move, ChessGame game);
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 = _halfMoveClock; gcd.FullMoveNumber = _fullMoveNumber; ChessGame copy = new ChessGame(gcd); copy.ApplyMove(move, true); return copy.IsInCheck(player); }
protected virtual CastlingType ApplyCastle(Move move) { CastlingType castle; int rank = move.Player == Player.White ? 1 : 8; File rookFile; File newRookFile; if (move.NewPosition.File == File.C) { castle = CastlingType.QueenSide; rookFile = File.A; newRookFile = File.D; } else { castle = CastlingType.KingSide; rookFile = File.H; newRookFile = File.F; } SetPieceAt(newRookFile, rank, new Rook(move.Player)); SetPieceAt(rookFile, rank, null); return castle; }
public MoreDetailedMove(Move move, Piece piece, bool isCapture, CastlingType castling, Piece capturedPiece, bool isEnpassant, bool isChecking, bool isCheckmate) : this(move.OriginalPosition, move.NewPosition, move.Player, move.Promotion, piece, isCapture, castling, capturedPiece, isEnpassant, isChecking, isCheckmate) { }
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); }
public virtual MoveType ApplyMove(Move move, bool alreadyValidated) { ChessUtilities.ThrowIfNull(move, "move"); 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); Piece newPiece = movingPiece; bool isCapture = capturedPiece != null; CastlingType castle = CastlingType.None; if (movingPiece is Pawn) { _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; 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); type |= MoveType.Promotion; } } else if (movingPiece is King) { if (movingPiece.Owner == Player.White) CanWhiteCastleKingSide = CanWhiteCastleQueenSide = false; else CanBlackCastleKingSide = CanBlackCastleQueenSide = false; if (new PositionDistance(move.OriginalPosition, move.NewPosition).DistanceX == 2 && CastlingCanBeLegal) { 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) 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; _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)) { _halfMoveClock++; if (_halfMoveClock >= 100) { fiftyMoves = true; } else { fiftyMoves = false; } } 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 MoveType ApplyMove(Move move, bool alreadyValidated) { Piece captured; return(ApplyMove(move, alreadyValidated, out captured)); }
protected bool IsValidMove(Move move, bool validateCheck) { ChessUtilities.ThrowIfNull(move, "move"); return(IsValidMove(move, validateCheck, true)); }
public virtual bool IsInCheck(Player player) { if (player == Player.None) { throw new ArgumentException("IsInCheck: Player.None is an invalid argument."); } Cache <bool> cache = player == Player.White ? inCheckCacheWhite : inCheckCacheBlack; if (cache.CachedAt == Moves.Count) { return(cache.Value); } Position kingPos = new Position(File.None, -1); for (int r = 1; r <= Board.Length; r++) { for (int f = 0; f < Board[8 - r].Length; f++) { Piece curr = GetPieceAt((File)f, r); if (curr is King && curr.Owner == player) { kingPos = new Position((File)f, r); break; } } if (kingPos != new Position(File.None, -1)) { break; } } if (kingPos.File == File.None) { return(cache.UpdateCache(false, Moves.Count)); } for (int r = 1; r <= Board.Length; r++) { for (int f = 0; f < Board[8 - r].Length; f++) { Piece curr = GetPieceAt((File)f, r); if (curr == null) { continue; } Player p = curr.Owner; Move move = new Move(new Position((File)f, r), kingPos, p); List <Move> moves = new List <Move>(); if (curr is Pawn && ((move.NewPosition.Rank == 8 && move.Player == Player.White) || (move.NewPosition.Rank == 1 && move.Player == Player.Black))) { moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'Q')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'R')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'B')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'N')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'K')); } else { moves.Add(move); } foreach (Move m in moves) { if (IsValidMove(m, false, false)) { return(cache.UpdateCache(true, Moves.Count)); } } } } return(cache.UpdateCache(false, Moves.Count)); }
public bool ApplyMove(Move move, bool alreadyValidated) { Utilities.ThrowIfNull(move, "move"); return(ApplyMove(move, alreadyValidated, true)); }
protected virtual bool IsValidMoveKing(Move move) { Utilities.ThrowIfNull(move, "move"); PositionDistance distance = new PositionDistance(move.OriginalPosition, move.NewPosition); if ((distance.DistanceX != 1 || distance.DistanceY != 1) && (distance.DistanceX != 0 || distance.DistanceY != 1) && (distance.DistanceX != 1 || distance.DistanceY != 0) && (distance.DistanceX != 2 || distance.DistanceY != 0)) return false; if (distance.DistanceX != 2) return true; return CanCastle(move); }
protected virtual bool ApplyMove(Move move, bool alreadyValidated, bool validateHasAnyValidMoves) { Utilities.ThrowIfNull(move, "move"); if (!alreadyValidated && !IsValidMove(move)) { return(false); } ChessPiece movingPiece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); ChessPiece newPiece = movingPiece; if (movingPiece.Piece == Piece.Pawn) { PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition); if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition).Piece == Piece.None) { // en passant SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, ChessPiece.None); } if (move.NewPosition.Rank == (move.Player == Player.White ? Rank.Eight : Rank.One)) { newPiece = new ChessPiece(move.Promotion, move.Player); } } else if (movingPiece.Piece == Piece.King) { if (movingPiece.Player == Player.White) { _whiteKingMoved = true; } else { _blackKingMoved = true; } if (new PositionDistance(move.OriginalPosition, move.NewPosition).DistanceX == 2) { Rank rank = move.Player == Player.White ? Rank.One : Rank.Eight; File rookFile = move.NewPosition.File == File.C ? File.A : File.H; File newRookFile = move.NewPosition.File == File.C ? File.D : File.F; SetPieceAt(newRookFile, rank, new ChessPiece(Piece.Rook, move.Player)); SetPieceAt(rookFile, rank, ChessPiece.None); } } else if (movingPiece.Piece == Piece.Rook) { if (move.Player == Player.White) { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == Rank.One) { _whiteRookAMoved = true; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == Rank.One) { _whiteRookHMoved = true; } } else { if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == Rank.Eight) { _blackRookAMoved = true; } else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == Rank.Eight) { _blackRookHMoved = true; } } } SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece); SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, ChessPiece.None); WhoseTurn = Utilities.GetOpponentOf(move.Player); _moves.Add(move); return(true); }
protected virtual bool IsValidMovePawn(Move move) { Utilities.ThrowIfNull(move, "move"); PositionDistance posDelta = new PositionDistance(move.OriginalPosition, move.NewPosition); if ((posDelta.DistanceX != 0 || posDelta.DistanceY != 1) && (posDelta.DistanceX != 1 || posDelta.DistanceY != 1) && (posDelta.DistanceX != 0 || posDelta.DistanceY != 2)) return false; if (move.Player == Player.White) { if ((int)move.OriginalPosition.Rank < (int)move.NewPosition.Rank) return false; if (move.NewPosition.Rank == Rank.Eight && move.Promotion == Piece.None) return false; } if (move.Player == Player.Black) { if ((int)move.OriginalPosition.Rank > (int)move.NewPosition.Rank) return false; if (move.NewPosition.Rank == Rank.One && move.Promotion == Piece.None) return false; } bool checkEnPassant = false; if (posDelta.DistanceY == 2) { if ((move.OriginalPosition.Rank != Rank.Two && move.Player == Player.White) || (move.OriginalPosition.Rank != Rank.Seven && move.Player == Player.Black)) return false; if (move.OriginalPosition.Rank == Rank.Two && GetPieceAt(move.OriginalPosition.File, Rank.Three).Piece != Piece.None) return false; if (move.OriginalPosition.Rank == Rank.Seven && GetPieceAt(move.OriginalPosition.File, Rank.Six).Piece != Piece.None) return false; } if (posDelta.DistanceX == 0 && (posDelta.DistanceY == 1 || posDelta.DistanceY == 2)) { if (GetPieceAt(move.NewPosition).Player != Player.None) return false; } else { if (GetPieceAt(move.NewPosition).Player != Utilities.GetOpponentOf(move.Player)) checkEnPassant = true; if (GetPieceAt(move.NewPosition).Player == move.Player) return false; } if (checkEnPassant) { if (_moves.Count == 0) { return false; } if ((move.OriginalPosition.Rank != Rank.Five && move.Player == Player.White) || (move.OriginalPosition.Rank != Rank.Four && move.Player == Player.Black)) return false; Move latestMove = _moves[_moves.Count - 1]; if (latestMove.Player != Utilities.GetOpponentOf(move.Player)) return false; if (move.Player == Player.White) { if (latestMove.OriginalPosition.Rank != Rank.Seven || latestMove.NewPosition.Rank != Rank.Five) return false; } else // (m.Player == Players.Black) { if (latestMove.OriginalPosition.Rank != Rank.Two || latestMove.NewPosition.Rank != Rank.Four) return false; } if (move.NewPosition.File != latestMove.NewPosition.File) return false; } return true; }
/// <summary> /// 生成 SAN 字符串。 /// </summary> /// <param name="gameBeforeTheMove"></param> /// <returns></returns> public string GenerateSANString(ChessGame gameBeforeTheMove) { string SANResult; if (Castling.Equals(CastlingType.KingSide)) { SANResult = "O-O"; } else if (Castling.Equals(CastlingType.QueenSide)) { SANResult = "O-O-O"; } else { var sb = new System.Text.StringBuilder(); if (!(Piece is Pieces.Pawn)) { sb.Append(char.ToUpper(Piece.GetFenCharacter())); } Piece[][] board = gameBeforeTheMove.GetBoard(); List<Move> validMoves = new List<Move>(); for (int r = 0; r < 8; r++) { for (int f = 0; f < 8; f++) { if (board[r][f] != Piece) continue; Move m = new Move(new Position((File)f, 8 - r), this.NewPosition, this.Player, this.Promotion); if (gameBeforeTheMove.IsValidMove(m)) { validMoves.Add(m); } } } if (validMoves.Count == 0) throw new PgnException("This move " + this.ToString() + " is not valid for gameBeforeTheMove."); else if (validMoves.Count > 1) { bool fileUnique = true; bool rankUnique = true; foreach (var move in validMoves) { if(!(move.OriginalPosition.Equals(this.OriginalPosition))) { if (move.OriginalPosition.File == this.OriginalPosition.File) { fileUnique = false; } if (move.OriginalPosition.Rank == this.OriginalPosition.Rank) { rankUnique = false; } } } if (fileUnique) sb.Append((char)((int)'a' + (int)this.OriginalPosition.File)); else if (rankUnique) sb.Append(this.OriginalPosition.Rank.ToString()); else { sb.Append((char)((int)'a' + (int)this.OriginalPosition.File)); sb.Append(this.OriginalPosition.Rank.ToString()); } } if (IsCapture) sb.Append("x"); sb.Append(this.NewPosition.ToString().ToLower()); if (Promotion.HasValue) { sb.Append("="); sb.Append(Promotion.Value); } if (IsCheckmate.HasValue && IsCheckmate.Value) { sb.Append("#"); } else if (IsChecking.HasValue && IsChecking.Value) { sb.Append("+"); } SANResult = sb.ToString(); } try { ChessDotNet.PgnMoveReader.ParseMove(SANResult, Player, gameBeforeTheMove); } catch (PgnException) { throw new System.ArgumentException("This move " + SANResult + " is not valid for gameBeforeTheMove."); } catch (System.ArgumentException) { throw new System.ArgumentException("This move " + SANResult + " is not valid for gameBeforeTheMove."); } this._storedSANString = SANResult; return SANResult; }
protected virtual bool IsValidMoveKnight(Move move) { Utilities.ThrowIfNull(move, "move"); PositionDistance posDelta = new PositionDistance(move.OriginalPosition, move.NewPosition); if ((posDelta.DistanceX != 2 || posDelta.DistanceY != 1) && (posDelta.DistanceX != 1 || posDelta.DistanceY != 2)) return false; return true; }
public bool IsValidMove(Move move) { Utilities.ThrowIfNull(move, "move"); return IsValidMove(move, true); }
public virtual bool IsInCheck(Player player) { if (player == Player.None) { throw new ArgumentException("IsInCheck: Player.None is an invalid argument."); } Cache<bool> cache = player == Player.White ? inCheckCacheWhite : inCheckCacheBlack; if (cache.CachedAt == Moves.Count) { return cache.Value; } Position kingPos = new Position(File.None, -1); for (int r = 1; r <= Board.Length; r++) { for (int f = 0; f < Board[8 - r].Length; f++) { Piece curr = GetPieceAt((File)f, r); if (curr is King && curr.Owner == player) { kingPos = new Position((File)f, r); break; } } if (kingPos != new Position(File.None, -1)) { break; } } if (kingPos.File == File.None) return cache.UpdateCache(false, Moves.Count); for (int r = 1; r <= Board.Length; r++) { for (int f = 0; f < Board[8 - r].Length; f++) { Piece curr = GetPieceAt((File)f, r); if (curr == null) continue; Player p = curr.Owner; Move move = new Move(new Position((File)f, r), kingPos, p); List<Move> moves = new List<Move>(); if (curr is Pawn && ((move.NewPosition.Rank == 8 && move.Player == Player.White) || (move.NewPosition.Rank == 1 && move.Player == Player.Black))) { moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'Q')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'R')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'B')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'N')); moves.Add(new Move(move.OriginalPosition, move.NewPosition, move.Player, 'K')); } else { moves.Add(move); } foreach (Move m in moves) { if (IsValidMove(m, false, false)) { return cache.UpdateCache(true, Moves.Count); } } } } return cache.UpdateCache(false, Moves.Count); }
protected virtual bool CanCastle(Move move) { Utilities.ThrowIfNull(move, "move"); if (move.Player == Player.White) { if (move.OriginalPosition.File != File.E || move.OriginalPosition.Rank != Rank.One) return false; if (_whiteKingMoved || (Status.Event == GameEvent.Check && Status.PlayerWhoCausedEvent == Player.Black)) return false; if (move.NewPosition.File == File.C) { if (_whiteRookAMoved || GetPieceAt(File.D, Rank.One).Piece != Piece.None || GetPieceAt(File.C, Rank.One).Piece != Piece.None || GetPieceAt(File.B, Rank.One).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.D, Rank.One), Player.White), Player.White) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.C, Rank.One), Player.White), Player.White)) return false; } else { if (_whiteRookHMoved || GetPieceAt(File.F, Rank.One).Piece != Piece.None || GetPieceAt(File.G, Rank.One).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.F, Rank.One), Player.White), Player.White) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.G, Rank.One), Player.White), Player.White)) return false; } } else { if (move.OriginalPosition.File != File.E || move.OriginalPosition.Rank != Rank.Eight) return false; if (_blackKingMoved || (Status.Event == GameEvent.Check && Status.PlayerWhoCausedEvent == Player.White)) return false; if (move.NewPosition.File == File.C) { if (_blackRookAMoved || GetPieceAt(File.D, Rank.Eight).Piece != Piece.None || GetPieceAt(File.C, Rank.Eight).Piece != Piece.None || GetPieceAt(File.B, Rank.Eight).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.D, Rank.Eight), Player.Black), Player.Black) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.C, Rank.Eight), Player.Black), Player.Black)) return false; } else { if (_blackRookHMoved || GetPieceAt(File.F, Rank.Eight).Piece != Piece.None || GetPieceAt(File.G, Rank.Eight).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.F, Rank.Eight), Player.Black), Player.Black) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.G, Rank.Eight), Player.Black), Player.Black)) return false; } } return true; }
public bool IsValidMove(Move move) { Utilities.ThrowIfNull(move, "move"); return(IsValidMove(move, true)); }
protected virtual bool IsValidMoveBishop(Move move) { Utilities.ThrowIfNull(move, "move"); PositionDistance posDelta = new PositionDistance(move.OriginalPosition, move.NewPosition); if (posDelta.DistanceX != posDelta.DistanceY) return false; bool increasingRank = (int)move.NewPosition.Rank > (int)move.OriginalPosition.Rank; bool increasingFile = (int)move.NewPosition.File > (int)move.OriginalPosition.File; for (int f = (int)move.OriginalPosition.File + (increasingFile ? 1 : -1), r = (int)move.OriginalPosition.Rank + (increasingRank ? 1 : -1); increasingFile ? f < (int)move.NewPosition.File : f > (int)move.NewPosition.File; f += increasingFile ? 1 : -1, r += increasingRank ? 1 : -1) { if (Board[r][f].Player != Player.None) { return false; } } return true; }
protected virtual bool CanCastle(Move move) { Utilities.ThrowIfNull(move, "move"); if (move.Player == Player.White) { if (move.OriginalPosition.File != File.E || move.OriginalPosition.Rank != Rank.One) { return(false); } if (_whiteKingMoved || (Status.Event == GameEvent.Check && Status.PlayerWhoCausedEvent == Player.Black)) { return(false); } if (move.NewPosition.File == File.C) { if (_whiteRookAMoved || GetPieceAt(File.D, Rank.One).Piece != Piece.None || GetPieceAt(File.C, Rank.One).Piece != Piece.None || GetPieceAt(File.B, Rank.One).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.D, Rank.One), Player.White), Player.White) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.C, Rank.One), Player.White), Player.White)) { return(false); } } else { if (_whiteRookHMoved || GetPieceAt(File.F, Rank.One).Piece != Piece.None || GetPieceAt(File.G, Rank.One).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.F, Rank.One), Player.White), Player.White) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.One), new Position(File.G, Rank.One), Player.White), Player.White)) { return(false); } } } else { if (move.OriginalPosition.File != File.E || move.OriginalPosition.Rank != Rank.Eight) { return(false); } if (_blackKingMoved || (Status.Event == GameEvent.Check && Status.PlayerWhoCausedEvent == Player.White)) { return(false); } if (move.NewPosition.File == File.C) { if (_blackRookAMoved || GetPieceAt(File.D, Rank.Eight).Piece != Piece.None || GetPieceAt(File.C, Rank.Eight).Piece != Piece.None || GetPieceAt(File.B, Rank.Eight).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.D, Rank.Eight), Player.Black), Player.Black) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.C, Rank.Eight), Player.Black), Player.Black)) { return(false); } } else { if (_blackRookHMoved || GetPieceAt(File.F, Rank.Eight).Piece != Piece.None || GetPieceAt(File.G, Rank.Eight).Piece != Piece.None || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.F, Rank.Eight), Player.Black), Player.Black) || WouldBeInCheckAfter(new Move(new Position(File.E, Rank.Eight), new Position(File.G, Rank.Eight), Player.Black), Player.Black)) { return(false); } } } return(true); }
protected virtual bool IsValidMoveQueen(Move move) { Utilities.ThrowIfNull(move, "move"); return IsValidMoveBishop(move) || IsValidMoveRook(move); }
protected virtual bool IsValidMovePawn(Move move) { Utilities.ThrowIfNull(move, "move"); PositionDistance posDelta = new PositionDistance(move.OriginalPosition, move.NewPosition); if ((posDelta.DistanceX != 0 || posDelta.DistanceY != 1) && (posDelta.DistanceX != 1 || posDelta.DistanceY != 1) && (posDelta.DistanceX != 0 || posDelta.DistanceY != 2)) { return(false); } if (move.Player == Player.White) { if ((int)move.OriginalPosition.Rank < (int)move.NewPosition.Rank) { return(false); } if (move.NewPosition.Rank == Rank.Eight && move.Promotion == Piece.None) { return(false); } } if (move.Player == Player.Black) { if ((int)move.OriginalPosition.Rank > (int)move.NewPosition.Rank) { return(false); } if (move.NewPosition.Rank == Rank.One && move.Promotion == Piece.None) { return(false); } } bool checkEnPassant = false; if (posDelta.DistanceY == 2) { if ((move.OriginalPosition.Rank != Rank.Two && move.Player == Player.White) || (move.OriginalPosition.Rank != Rank.Seven && move.Player == Player.Black)) { return(false); } if (move.OriginalPosition.Rank == Rank.Two && GetPieceAt(move.OriginalPosition.File, Rank.Three).Piece != Piece.None) { return(false); } if (move.OriginalPosition.Rank == Rank.Seven && GetPieceAt(move.OriginalPosition.File, Rank.Six).Piece != Piece.None) { return(false); } } if (posDelta.DistanceX == 0 && (posDelta.DistanceY == 1 || posDelta.DistanceY == 2)) { if (GetPieceAt(move.NewPosition).Player != Player.None) { return(false); } } else { if (GetPieceAt(move.NewPosition).Player != Utilities.GetOpponentOf(move.Player)) { checkEnPassant = true; } if (GetPieceAt(move.NewPosition).Player == move.Player) { return(false); } } if (checkEnPassant) { if (_moves.Count == 0) { return(false); } if ((move.OriginalPosition.Rank != Rank.Five && move.Player == Player.White) || (move.OriginalPosition.Rank != Rank.Four && move.Player == Player.Black)) { return(false); } Move latestMove = _moves[_moves.Count - 1]; if (latestMove.Player != Utilities.GetOpponentOf(move.Player)) { return(false); } if (move.Player == Player.White) { if (latestMove.OriginalPosition.Rank != Rank.Seven || latestMove.NewPosition.Rank != Rank.Five) { return(false); } } else // (m.Player == Players.Black) { if (latestMove.OriginalPosition.Rank != Rank.Two || latestMove.NewPosition.Rank != Rank.Four) { return(false); } } if (move.NewPosition.File != latestMove.NewPosition.File) { return(false); } } return(true); }
public bool ApplyMove(Move move, bool alreadyValidated) { Utilities.ThrowIfNull(move, "move"); return ApplyMove(move, alreadyValidated, true); }
protected virtual bool IsValidMoveQueen(Move move) { Utilities.ThrowIfNull(move, "move"); return(IsValidMoveBishop(move) || IsValidMoveRook(move)); }
protected virtual ReadOnlyCollection<Move> GetValidMovesKnight(Position from, bool returnIfAny) { Utilities.ThrowIfNull(from, "from"); List<Move> validMoves = new List<Move>(); ChessPiece cp = GetPieceAt(from); int l0 = Board.Length; int l1 = Board[0].Length; int[][] directions = new int[][] { new int[] { 2, 1 }, new int[] { -2, -1 }, new int[] { 1, 2 }, new int[] { -1, -2 }, new int[] { 1, -2 }, new int[] { -1, 2 }, new int[] { 2, -1 }, new int[] { -2, 1 } }; foreach (int[] dir in directions) { if ((int)from.File + dir[0] < 0 || (int)from.File + dir[0] >= l1 || (int)from.Rank + dir[1] < 0 || (int)from.Rank + dir[1] >= l0) continue; Move move = new Move(from, new Position(from.File + dir[0], from.Rank + dir[1]), cp.Player); if (IsValidMove(move)) { validMoves.Add(move); if (returnIfAny) return new ReadOnlyCollection<Move>(validMoves); } } return new ReadOnlyCollection<Move>(validMoves); }
protected virtual bool IsValidMove(Move move, bool validateCheck) { Utilities.ThrowIfNull(move, "move"); if (move.OriginalPosition.Equals(move.NewPosition)) { return(false); } ChessPiece piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank); if (move.Player != WhoseTurn) { return(false); } if (piece.Player != move.Player) { return(false); } if (GetPieceAt(move.NewPosition).Player == move.Player) { return(false); } switch (piece.Piece) { case Piece.King: if (!IsValidMoveKing(move)) { return(false); } break; case Piece.Pawn: if (!IsValidMovePawn(move)) { return(false); } break; case Piece.Queen: if (!IsValidMoveQueen(move)) { return(false); } break; case Piece.Rook: if (!IsValidMoveRook(move)) { return(false); } break; case Piece.Bishop: if (!IsValidMoveBishop(move)) { return(false); } break; case Piece.Knight: if (!IsValidMoveKnight(move)) { return(false); } break; default: return(false); } if (validateCheck && WouldBeInCheckAfter(move, move.Player)) { return(false); } return(true); }
protected virtual bool WouldBeInCheckAfter(Move move, Player player) { Utilities.ThrowIfNull(move, "move"); ChessGame copy = new ChessGame(Board, player, false); copy.ApplyMove(move, true, false); GameStatus status = copy.CalculateStatus(player, false); return status.Event == GameEvent.Check && status.PlayerWhoCausedEvent != player; }
protected bool IsValidMove(Move move, bool validateCheck) { ChessUtilities.ThrowIfNull(move, "move"); return IsValidMove(move, validateCheck, true); }