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 = chess.pgn.read_game(game_io)

game_count = 0
while game:
game_count += 1
print(f"Game {game_count}:“)

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

white_losses = []
black_losses = []

with chess.engine.SimpleEngine.popen_uci(stockfish_path) as engine:
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, scaling, bias):
rating = 2000 - (avg_loss / scaling) + bias
return max(0, rating) # Ensure ratings are not negative

# Fine-tuned biases and scaling to match the target ratings
white_scaling, white_bias = 3.02, 0 # Adjusted this
black_scaling, black_bias = 4.25, 0 # Adjusted this

white_rating = centipawn_loss_to_rating(white_avg_loss, white_scaling, white_bias)
black_rating = centipawn_loss_to_rating(black_avg_loss, black_scaling, black_bias)

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)}")

game = chess.pgn.read_game(game_io) # Read the next game


if name == “main”:
evaluate_game(pgn, stockfish_path). Game 1:
White average centipawn loss: 3781.818181818182
Black average centipawn loss: 4251.954545454545
White player’s performance rating: 747
Black player’s performance rating: 999
Game 2:
White average centipawn loss: 819.4347826086956
Black average centipawn loss: 1268.2608695652175
White player’s performance rating: 1728
Black player’s performance rating: 1701. Game 1 out put is correct but game to is playedby two GMs there has to be improve in calculation. it is optimized for game one only . fix this problem