Skip to content

Conversation

@Amir-Zucker
Copy link
Contributor

@Amir-Zucker Amir-Zucker commented Jan 26, 2025

This PR addresses an issue where pawn promotion doesn't reflect in the original move object inside MoveTree.

If promoting a piece by using the game.make(move: from:) function, the game object does not know of the user selected piece after the promotion, nor does it update the move object at any point.

So for example if we initialize a game object with the following fen: "4kb1r/Pb2qpp1/2pp1n1p/1rn1p3/4P3/1BNP1N2/2P2PPP/R1BQ1RK1 w k - 1 14"

the move pawn on a7 to a8 will be annotated by the SANParser as simply "a8" since the value for promotedPiece is nil.

I didn't want to tie board and game objects because those should be able to operate independently, so I passed the responsibility of notifying the game object about the promoted piece to the developer.

…moves_list - fix pawn promotion in MoveTreeObject
@pdil pdil added the bug A bug or issue that should be resolved label Feb 5, 2025
@pdil pdil self-requested a review February 5, 2025 03:26
@pdil
Copy link
Member

pdil commented Jun 4, 2025

This can probably be better explained in the documentation but the user is supposed to use Board to make moves and promote and once the final Move object is obtained then one can call Game.make(move:from:) to update the Game's positions and move tree. Game is not intended to be a standalone way to make moves since it does not perform any validations of move legality (that's all done in Board).

I think this is definitely something that can be explained better in the documentation or API design however so I will investigate this further.

@Amir-Zucker
Copy link
Contributor Author

Amir-Zucker commented Jun 6, 2025

I understand, but my reasoning is that if you only update the game object once the move is finalized, you would have to check every move if it's not a promotion move before sending it to the game object. Not to mention there is no easy way for the developer to know that it's a promotion move at the time of making the move, since move.promotedPiece is populated after board.completePromotion(of _: to _:) is called.

        if let move = board.move(pieceAt: startingSquare, to: endingSquare) {
//          Move is not a pawn we can send it to game object directly
            if move.piece.kind != .pawn || 
//              Move does not results in white promoting
                (move.piece.color == .white && move.end.rank != 8) ||
//              Move does not results in black promoting 
                (move.piece.color == .black && move.end.rank != 1) { 
                currentIndex = game.make(move: move, from: currentIndex)
            } else {
                promotionMove = move
//              A player is promoting a piece, should store the promotion move and wait for promotion to complete before sending it to game object.
            }
        }
//      ...
        func completePromotion(to kind: Piece.Kind) {
            if let promotionMove {
                let updatedMove = board.completePromotion(of: promotionMove, to: kind)
                currentIndex = game.make(move: updatedMove, from: currentIndex)
            }
        }

whereas if you implement my changes, you streamline the process. The developer always update the game object and if it happens to be a promotion move, they would simply amend the last move after the promotion was completed.

        if let move = board.move(pieceAt: startingSquare, to: endingSquare) {
            currentIndex = game.make(move: move, from: currentIndex)
        }
//      ...
        func completePromotion(to kind: Piece.Kind) {
//          This can't be used in the previous example as current index is still pointing to the move before the promotion move.
            if let move = game.moves[currentIndex] {
                board.completePromotion(of: move, to: kind)
//              no need to update the index here as it's already pointing at the correct index.
                game.completePromotion(of: move, to: kind)
            }
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug A bug or issue that should be resolved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants