import chess.pgn
import chess.engine
import io
import numpy as np

# Set the path to your Stockfish engine
stockfish_path = "F:/Fearless songs/stockfish-windows-x86-64-avx2/stockfish/stockfish-windows-x86-64-avx2"

# Sample PGN with multiple games
pgn = """
[Event "Live Chess"]
[Site "Chess.com"]
[Date "2024.07.01"]
[Round "-"]
[White "OldManMinerva"]
[Black "Shaaruk445"]
[Result "0-1"]

1. d4 d5 2. Nf3 Nf6 3. Nbd2 Nc6 4. c3 Bg4 5. g3 e5 6. Bg2 Bxf3 7. Nxf3 e4 8. Nd2 Bd6 9. e3 Qe7 10. O-O h5 11. Qc2 h4 12. c4 hxg3 13. fxg3 Ng4 14. Nb3 Rh2 15. cxd5 Bxg3 16. dxc6 Qh4 17. cxb7 Rh1+ 18. Bxh1 Rb8 19. Qc6+ Kf8 20. Qc5+ Kg8 21. Qc2 Bh2+ 22. Qxh2 Qxh2#

[Event "Live Chess"]
[Site "Chess.com"]
[Date "2024.06.30"]
[Round "?"]
[White "Rurep26"]
[Black "GMHess"]
[Result "0-1"]
[ECO "B06"]
[WhiteElo "2773"]
[BlackElo "2937"]
[TimeControl "180"]
[EndTime "23:58:29 PDT"]
[Termination "GMHess won by resignation"]

1. d4 g6 2. e4 Bg7 3. Nc3 c5 4. Be3 cxd4 5. Bxd4 Nf6 6. Qd2 Nc6 7. Be3 O-O 8. f3 Qa5 9. O-O-O d5 10. exd5 Nb4 11. Bc4 Bf5 12. Bb3 Rac8 13. Nge2 Rfd8 14. Nd4 Nfxd5 15. Nxd5 Rxd5 16. Nxf5 Rxd2 17. Nxe7+ Kf8 18. Bxd2 Nd3+ 19. Kb1 Qe5 20. c3 Qxe7 21. Bc2 Nxb2 22. Kxb2 Qb4+ 23. Bb3 Rxc3 0-1
"""


def evaluate_game(pgn_str, stockfish_path):
    game_io = io.StringIO(pgn_str)
    game_count = 0

    with chess.engine.SimpleEngine.popen_uci(stockfish_path) as engine:
        while True:
            game = chess.pgn.read_game(game_io)
            if game is None:
                break

            game_count += 1
            print(f"\nGame {game_count}:")

            board = game.board()
            move_count = 0
            node = game

            white_losses = []
            black_losses = []

            while node.variations:
                next_node = node.variation(0)
                move = next_node.move

                # Get Stockfish evaluation before the move
                info = engine.analyse(board, chess.engine.Limit(time=0.1))
                score_before = info["score"].relative.score(mate_score=10000)

                board.push(move)

                # Get Stockfish evaluation after the move
                info = engine.analyse(board, chess.engine.Limit(time=0.1))
                score_after = info["score"].relative.score(mate_score=10000)

                # Calculate centipawn loss
                if score_before is not None and score_after is not None:
                    centipawn_loss = abs(score_before - score_after)
                    if board.turn == chess.BLACK:
                        white_losses.append(centipawn_loss)
                    else:
                        black_losses.append(centipawn_loss)

                node = next_node
                move_count += 1

            # Calculate average centipawn loss
            white_avg_loss = np.mean(white_losses) if white_losses else 0
            black_avg_loss = np.mean(black_losses) if black_losses else 0

            # Adjust the performance rating calculation
            def centipawn_loss_to_rating(avg_loss, is_white):
                if is_white:
                    if avg_loss >= 3800:
                        return 750
                    elif avg_loss >= 800:
                        return 3100 - (avg_loss - 800) * 0.1875
                    else:
                        return 2900 + (800 - avg_loss) * 0.125
                else:
                    if avg_loss >= 4250:
                        return 1000
                    elif avg_loss >= 1249:
                        return 2850 - (avg_loss - 1249) * 0.64
                    else:
                        return 2900 + (1249 - avg_loss) * 0.16

            white_rating = centipawn_loss_to_rating(white_avg_loss, True)
            black_rating = centipawn_loss_to_rating(black_avg_loss, False)

            print(f"White average centipawn loss: {white_avg_loss}")
            print(f"Black average centipawn loss: {black_avg_loss}")
            print(f"White player’s performance rating: {int(white_rating)}")
            print(f"Black player’s performance rating: {int(black_rating)}")


if __name__ == "__main__":
    evaluate_game(pgn, stockfish_path)
. out put is Game 1:
White average centipawn loss: 3763.5
Black average centipawn loss: 4236.454545454545
White player’s performance rating: 2544
Black player’s performance rating: 938

Game 2:
White average centipawn loss: 807.1304347826087
Black average centipawn loss: 1241.304347826087
White player’s performance rating: 3098
Black player’s performance rating: 2901. only game 1 White rating has to be close to 750. and black : 1000