-
Notifications
You must be signed in to change notification settings - Fork 14
Description
Summary
After white castles kingside (O-O), black cannot castle kingside (O-O) even though the FEN notation indicates that black retains both castling rights (kq). The move is rejected as invalid, and ValidMoves() does not include the kingside castling option for black.
Environment
- Library:
github.com/corentings/chess/v2 - Version:
v2.3.4-0.20251212145753-cc2b8b7ca2b4(or latest main branch) - Go Version: 1.22.0+
Steps to Reproduce
-
Start from a position where both sides have all castling rights:
FEN: r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1 -
White castles kingside:
O-O -
Attempt to castle kingside as black:
O-O
Expected Behavior
Black should be able to castle kingside after white has castled kingside, since:
- The FEN after white's move shows
kq(both castling rights available for black) - The black king and rook are in their original positions
- No pieces are blocking the castling path
- The king is not in check
Actual Behavior
ValidMoves()does not return a kingside castling move for black- Attempting to decode
O-Ofor black results in:chess: move O-O is not valid - Attempting to use UCI notation
e8g8also fails:move e8g8 is not valid for the current position - Black can still castle queenside (
O-O-O) successfully
Test Case
package main
import (
"fmt"
"github.com/corentings/chess/v2"
)
func main() {
// Starting position with all castling rights
fen, _ := chess.FEN("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")
g := chess.NewGame(fen)
fmt.Printf("Initial FEN: %s\n", g.Position().String())
// White castles kingside
pos := g.Position()
move, _ := chess.AlgebraicNotation{}.Decode(pos, "O-O")
g.Move(move, nil)
fmt.Printf("After white O-O, FEN: %s\n", g.Position().String())
// FEN shows: r3k2r/8/8/8/8/8/8/R4RK1 b kq - 1 1
// Note: 'kq' indicates black should have both castling rights
// Check valid moves for black
validMoves := g.ValidMoves()
hasKingside := false
for _, m := range validMoves {
if m.HasTag(chess.KingSideCastle) {
hasKingside = true
fmt.Printf("Black can castle kingside: %s\n", m.String())
}
}
if !hasKingside {
fmt.Println("BUG: Black cannot castle kingside (but FEN shows 'kq')")
}
// Try to manually decode black's kingside castle
pos = g.Position()
move, err := chess.AlgebraicNotation{}.Decode(pos, "O-O")
if err != nil {
fmt.Printf("BUG: Cannot decode black O-O: %v\n", err)
} else {
if err := g.Move(move, nil); err != nil {
fmt.Printf("BUG: Cannot apply black O-O: %v\n", err)
}
}
}Additional Observations
- The issue appears to be specific to kingside castling after the opponent has castled kingside
- Queenside castling works correctly in the same position
- The FEN notation correctly preserves the castling rights (
kq), but the move validation logic appears to incorrectly reject the move - This suggests the issue is in the castling validation logic, not in FEN parsing
Impact
This bug prevents legitimate castling moves in games where one player has already castled kingside, which is a common scenario in chess games.
Related
This issue was also present in the archived notnil/chess repository, suggesting it may be a long-standing bug that was carried over to the new fork.