rudzen / ChessLib

C# chess library containing a complete data structure and move generation.
MIT License
81 stars 22 forks source link

Position.IsLegal(Move) returns true for many moves that are not legal #64

Open primitiveType opened 1 year ago

primitiveType commented 1 year ago

Perhaps there's a different endpoint I should be using to determine whether a move is legal. But when developing a UI with this library, I need a way to determine whether a player-input move is legal. This function sounds like the right one, however it only checks for specific illegal moves- it doesn't check for instance whether the position the piece is moving to is within its capabilities. For instance, I can move a pawn sideways.

I would expect the following test to pass:

    public void MoveIsLegal()
    {
        var illegalMove = Move.Create(Square.F2, Square.F6);

        // construct game and start a new game
        var game = GameFactory.Create(Fen.Fen.StartPositionFen);
        var position = game.Pos;
        var state = new State();

        // verify in check is actually true
        Assert.False(position.IsLegal(illegalMove));
    }
rudzen commented 1 year ago

Let me see if I understand this correctly.

You wish to determine whether or not a move can be performed, based on the source piece being attempted to move to somewhere else on the board.

The Position.IsLegal(Move) method actually expects the move you pass in the be a legal move, in fact the move generator use this method to assist with legal state detection. This is possible because the moves being checked are always "actual" moves based on the rules of chess for the various pieces.

You would have to check that based on the legal moves from the current position.

  1. You would need to convert the move into something more accurate that the library can understand.
  2. Then iterate through the legal moves and check if that move is one of the legal moves.

This sounds like the same kind of solution when parsing in a position and a chain of moves from let's say the UCI protocol. There you typically have the startposition followed by all the moves performed so far. These moves would need to be converted into something move useful that just a source and a destination move.

Something along the lines of (and you can use the move list pool here as well):

public Move MoveFromUci(IPosition pos, ReadOnlySpan<char> uciMove)
{
    var moveList = pos.GenerateMoves();
    var moves = moveList.Get();

    foreach (var move in moves)
    {
        if (uciMove.Equals(move.Move.ToString(), StringComparison.InvariantCultureIgnoreCase))
            return move.Move;
    }

    return Move.EmptyMove;
}

This will accept the position and the uci move fx. "a2a3" and then return the actual Move that matches of Move.EmptyMove if no move exists that matches.

Hope it helps.