diff --git a/nakama/go-modules/main.go b/nakama/go-modules/main.go index af4365b..7fab08a 100644 --- a/nakama/go-modules/main.go +++ b/nakama/go-modules/main.go @@ -700,6 +700,20 @@ func (m *ChessMatch) MatchLeave(ctx context.Context, logger runtime.Logger, db * }) dispatcher.BroadcastMessage(OpCodeGameOver, msg, nil, nil, true) + // Update match label to finished so it's not detected as active + label := MatchLabel{ + Game: "chess960", + Status: "finished", + Result: s.Result, + White: s.WhiteName, + WhiteID: s.WhiteID, + Black: s.BlackName, + BlackID: s.BlackID, + PositionID: s.PositionID, + } + labelJSON, _ := json.Marshal(label) + dispatcher.MatchLabelUpdate(string(labelJSON)) + logger.Info("Game forfeited: %s", s.Result) } } @@ -753,14 +767,77 @@ type MoveResult struct { Reason string } +// Convert Chess960 FEN castling notation to standard notation for chess library compatibility +func convertChess960FenForLibrary(fenStr string) string { + parts := strings.Split(fenStr, " ") + if len(parts) < 3 { + return fenStr + } + + castling := parts[2] + // Check if it's already standard notation or empty + if castling == "-" || castling == "KQkq" || castling == "KQ" || castling == "kq" || + castling == "K" || castling == "Q" || castling == "k" || castling == "q" || + castling == "Kq" || castling == "Qk" || castling == "Kk" || castling == "Qq" { + return fenStr + } + + // Convert Chess960 file-based notation (like HBhb) to standard KQkq + newCastling := "" + hasWhiteKingside := false + hasWhiteQueenside := false + hasBlackKingside := false + hasBlackQueenside := false + + for _, c := range castling { + if c >= 'A' && c <= 'H' { + // White castling - higher file = kingside, lower = queenside + if c >= 'E' { + hasWhiteKingside = true + } else { + hasWhiteQueenside = true + } + } else if c >= 'a' && c <= 'h' { + // Black castling + if c >= 'e' { + hasBlackKingside = true + } else { + hasBlackQueenside = true + } + } + } + + if hasWhiteKingside { + newCastling += "K" + } + if hasWhiteQueenside { + newCastling += "Q" + } + if hasBlackKingside { + newCastling += "k" + } + if hasBlackQueenside { + newCastling += "q" + } + + if newCastling == "" { + newCastling = "-" + } + + parts[2] = newCastling + return strings.Join(parts, " ") +} + // Validate chess move using corentings/chess/v2 library func validateChessMove(fenStr, from, to, promotion string, logger runtime.Logger) MoveResult { result := MoveResult{Turn: "w"} - logger.Info("validateChessMove: FEN=%s, move=%s%s", fenStr, from, to) + // Convert Chess960 castling notation to standard for library compatibility + convertedFen := convertChess960FenForLibrary(fenStr) + logger.Info("validateChessMove: original FEN=%s, converted=%s, move=%s%s", fenStr, convertedFen, from, to) // Parse FEN - fen, err := chess.FEN(fenStr) + fen, err := chess.FEN(convertedFen) if err != nil { logger.Error("validateChessMove: FEN parse error: %v", err) return result