Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Black Cannot Castle Kingside After White Castles Kingside #82

@tmountain

Description

@tmountain

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

  1. Start from a position where both sides have all castling rights:

    FEN: r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1
    
  2. White castles kingside: O-O

  3. 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-O for black results in: chess: move O-O is not valid
  • Attempting to use UCI notation e8g8 also 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions