@@ -2261,3 +2261,115 @@ func TestIgnoreInsufficientMaterialDraw(t *testing.T) {
22612261 t .Fatal ("ignoreInsufficientMaterialDraw should be true after being ignored" )
22622262 }
22632263}
2264+
2265+ func TestCastlingInteractions (t * testing.T ) {
2266+ tests := []struct {
2267+ name string
2268+ fen string
2269+ firstMove string
2270+ secondMove string
2271+ shouldAllow bool
2272+ }{
2273+ // No Pawns (Blocked)
2274+ {
2275+ name : "No Pawns: White O-O then Black O-O" ,
2276+ fen : "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1" ,
2277+ firstMove : "O-O" ,
2278+ secondMove : "O-O" ,
2279+ shouldAllow : false ,
2280+ },
2281+ {
2282+ name : "No Pawns: White O-O-O then Black O-O-O" ,
2283+ fen : "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1" ,
2284+ firstMove : "O-O-O" ,
2285+ secondMove : "O-O-O" ,
2286+ shouldAllow : false ,
2287+ },
2288+ {
2289+ name : "No Pawns: Black O-O then White O-O" ,
2290+ fen : "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1" ,
2291+ firstMove : "O-O" ,
2292+ secondMove : "O-O" ,
2293+ shouldAllow : false ,
2294+ },
2295+ {
2296+ name : "No Pawns: Black O-O-O then White O-O-O" ,
2297+ fen : "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1" ,
2298+ firstMove : "O-O-O" ,
2299+ secondMove : "O-O-O" ,
2300+ shouldAllow : false ,
2301+ },
2302+ // With Pawns (Allowed)
2303+ {
2304+ name : "With Pawns: White O-O then Black O-O" ,
2305+ fen : "r3k2r/5p2/8/8/8/8/5P2/R3K2R w KQkq - 0 1" , // Pawns at f2, f7
2306+ firstMove : "O-O" ,
2307+ secondMove : "O-O" ,
2308+ shouldAllow : true ,
2309+ },
2310+ {
2311+ name : "With Pawns: White O-O-O then Black O-O-O" ,
2312+ fen : "r3k2r/3p4/8/8/8/8/3P4/R3K2R w KQkq - 0 1" , // Pawns at d2, d7
2313+ firstMove : "O-O-O" ,
2314+ secondMove : "O-O-O" ,
2315+ shouldAllow : true ,
2316+ },
2317+ {
2318+ name : "With Pawns: Black O-O then White O-O" ,
2319+ fen : "r3k2r/5p2/8/8/8/8/5P2/R3K2R b KQkq - 0 1" , // Pawns at f2, f7
2320+ firstMove : "O-O" ,
2321+ secondMove : "O-O" ,
2322+ shouldAllow : true ,
2323+ },
2324+ {
2325+ name : "With Pawns: Black O-O-O then White O-O-O" ,
2326+ fen : "r3k2r/3p4/8/8/8/8/3P4/R3K2R b KQkq - 0 1" , // Pawns at d2, d7
2327+ firstMove : "O-O-O" ,
2328+ secondMove : "O-O-O" ,
2329+ shouldAllow : true ,
2330+ },
2331+ }
2332+
2333+ for _ , tt := range tests {
2334+ t .Run (tt .name , func (t * testing.T ) {
2335+ fen , err := FEN (tt .fen )
2336+ if err != nil {
2337+ t .Fatalf ("Invalid FEN: %v" , err )
2338+ }
2339+ g := NewGame (fen )
2340+
2341+ // Make first move
2342+ pos := g .Position ()
2343+ m1 , err := AlgebraicNotation {}.Decode (pos , tt .firstMove )
2344+ if err != nil {
2345+ t .Fatalf ("Failed to decode first move %s: %v" , tt .firstMove , err )
2346+ }
2347+ if err := g .Move (m1 , nil ); err != nil {
2348+ t .Fatalf ("Failed to make first move %s: %v" , tt .firstMove , err )
2349+ }
2350+
2351+ // Check if second move is valid
2352+ validMoves := g .ValidMoves ()
2353+ isAllowed := false
2354+
2355+ // Determine expected tag based on second move string
2356+ var expectedTag MoveTag
2357+ if tt .secondMove == "O-O" {
2358+ expectedTag = KingSideCastle
2359+ } else {
2360+ expectedTag = QueenSideCastle
2361+ }
2362+
2363+ for _ , m := range validMoves {
2364+ if m .HasTag (expectedTag ) {
2365+ isAllowed = true
2366+ break
2367+ }
2368+ }
2369+
2370+ if isAllowed != tt .shouldAllow {
2371+ t .Errorf ("Castling allowed: %v, want: %v" , isAllowed , tt .shouldAllow )
2372+ }
2373+ })
2374+ }
2375+ }
0 commit comments