public List <Move> PawnMoves(ISquare pawn) { AssertType(pawn, PieceType.Pawn); byte yCoord = pawn.Location.YCoord; byte xCoord = pawn.Location.XCoord; List <Move> moves = new List <Move>(); if (LastRow(pawn)) { return(moves); } sbyte minusIfWhite = (sbyte)((pawn.Colour == PieceColour.White) ? -1 : 1); // Advance one square if not blocked by a piece of either colour if (this[xCoord, yCoord + minusIfWhite].Type == PieceType.None) { moves.Add(new Move(pawn.Location, new GridLocation(xCoord, (yCoord + minusIfWhite)))); // Advance two squares if not blocked and haven't moved yet, and take note of the enPassant square. if (pawn.HasMoved == false && this[xCoord, yCoord + 2 * minusIfWhite].Type == PieceType.None) { moves.Add(new Move(pawn.Location, new GridLocation(xCoord, (yCoord + 2 * minusIfWhite)), enPassantSquare: this[xCoord, yCoord + minusIfWhite])); } } // If not on the far left, can take the piece to its diagonal left if (xCoord != 0) { ISquare leftTarget = this[xCoord - 1, yCoord + minusIfWhite]; if (leftTarget.Type != PieceType.None && leftTarget.Colour != pawn.Colour) { moves.Add((new Move(pawn.Location, leftTarget.Location))); } else if (leftTarget == EnPassantSquare) { moves.Add(new Move(pawn, EnPassantSquare, sideEffect: new Move(EnPassantSquare.RelativeLocation(0, (sbyte)-minusIfWhite), null))); } } // If not on the far right, can take the piece to its diagonal right if (xCoord != 7) { ISquare rightTarget = this[xCoord + 1, yCoord + minusIfWhite]; if (rightTarget.Type != PieceType.None && rightTarget.Colour != pawn.Colour) { moves.Add(new Move(pawn, rightTarget)); } else if (rightTarget == EnPassantSquare) { moves.Add(new Move(pawn, EnPassantSquare, sideEffect: new Move(EnPassantSquare.RelativeLocation(0, (sbyte)-minusIfWhite), null))); } } return(moves); }
public bool Equals(State other) { if (ReferenceEquals(null, other)) { return(false); } // if (ReferenceEquals(this, other)) return true; return(LastMove.Equals(other.LastMove) && Key.Equals(other.Key) && PawnStructureKey.Equals(other.PawnStructureKey) && EnPassantSquare.Equals(other.EnPassantSquare) && CastlelingRights == other.CastlelingRights && NonPawnMaterial.First() == other.NonPawnMaterial.First() && NonPawnMaterial.Last() == other.NonPawnMaterial.Last() && PliesFromNull == other.PliesFromNull && Rule50 == other.Rule50 && Pinners.Equals(other.Pinners) && Checkers.Equals(other.Checkers) && CapturedPiece == other.CapturedPiece && Equals(Previous, other.Previous)); }
/// <summary> /// <para>"Validates" a move using simple logic. For example that the piece actually being moved exists etc.</para> /// <para>This is basically only useful while developing and/or debugging</para> /// </summary> /// <param name="move">The move to check for logical errors</param> /// <returns>True if move "appears" to be legal, otherwise false</returns> public bool IsPseudoLegal(Move move) { // Verify that the piece actually exists on the board at the location defined by the move struct if ((_bitboardPieces[move.GetMovingPiece().ToInt()] & move.GetFromSquare()).Empty()) { return(false); } var to = move.GetToSquare(); if (move.IsCastlelingMove()) { // TODO : Basic castleling verification if (CanCastle(move.GetFromSquare() < to ? ECastleling.Short : ECastleling.Long)) { return(true); } var mg = new MoveGenerator(Position); mg.GenerateMoves(); return(mg.Moves.Contains(move)); } else if (move.IsEnPassantMove()) { // TODO : En-passant here // TODO : Test with unit test var opponent = ~move.GetMovingSide(); if (EnPassantSquare.PawnAttack(opponent) & Position.Pieces(EPieceType.Pawn, opponent)) { return(true); } } else if (move.IsCaptureMove()) { var opponent = ~move.GetMovingSide(); if ((_occupiedBySide[opponent.Side] & to).Empty()) { return(false); } if ((_bitboardPieces[move.GetCapturedPiece().ToInt()] & to).Empty()) { return(false); } } else if ((_occupied & to) != 0) { return(false); } // ReSharper disable once SwitchStatementMissingSomeCases switch (move.GetMovingPiece().Type()) { case EPieceType.Bishop: case EPieceType.Rook: case EPieceType.Queen: if (move.GetFromSquare().BitboardBetween(to) & _occupied) { return(false); } break; } return(true); }