#!/usr/bin/env python3 import chess import chess.engine import time import sys # Path to the Stockfish executable STOCKFISH_PATH = "/home/tun08104/senior_design/stockfish_dwld/stockfish/src/stockfish" # Path to your custom NNUE file MY_NNUE_PATH = sys.argv[1] # Stockfish skill levels (0–20) EASY_SKILL = 2 INTERMEDIATE_SKILL = 10 STRONG_SKILL = 20 # Default Stockfish strength # Time control per move (seconds) MOVE_TIME = 0.05 # Games to play GAMES = 20 # Opponent difficulty selection: "easy", "intermediate", "strong" OPPONENT = "intermediate" # ===================== # INTERNAL SETUP # ===================== def make_engine(nnue_path=None, skill=None): """Create a Stockfish engine with optional NNUE override + skill level.""" engine = chess.engine.SimpleEngine.popen_uci(STOCKFISH_PATH) if nnue_path is not None: engine.configure({"EvalFile": nnue_path}) if skill is not None: engine.configure({"Skill Level": skill}) return engine def play_game(engine_white, engine_black, move_time): """Play a single game and return result: 1 = white win, 0 = draw, -1 = black win.""" board = chess.Board() while not board.is_game_over(): engine = engine_white if board.turn == chess.WHITE else engine_black try: result = engine.play(board, chess.engine.Limit(time=move_time)) except Exception as e: print("Engine crashed or timed out:", e) return 0 if result.move is None: break board.push(result.move) outcome = board.outcome() if outcome is None: return 0 if outcome.winner is True: return 1 elif outcome.winner is False: return -1 else: return 0 def main(): print("Launching engines...") # Decide opponent skill if OPPONENT == "easy": opp_skill = EASY_SKILL elif OPPONENT == "intermediate": opp_skill = INTERMEDIATE_SKILL else: opp_skill = STRONG_SKILL # Custom NNUE engine my_engine = make_engine(nnue_path=MY_NNUE_PATH, skill=20) # Opponent Stockfish engine opp_engine = make_engine(nnue_path=None, skill=opp_skill) print(f"Opponent skill level = {opp_skill}") print(f"Testing over {GAMES} games...\n") scores = {"win": 0, "loss": 0, "draw": 0} for i in range(1, GAMES + 1): print(f"=== Game {i} ===") # Alternate colors every game if i % 2 == 1: white = my_engine black = opp_engine my_color = "White" else: white = opp_engine black = my_engine my_color = "Black" result = play_game(white, black, MOVE_TIME) # Interpret score from my_engine perspective if result == 1 and my_color == "White": scores["win"] += 1 print("My NNUE wins") elif result == -1 and my_color == "Black": scores["win"] += 1 print("My NNUE wins") elif result == 0: scores["draw"] += 1 print("Draw") else: scores["loss"] += 1 print("My NNUE loses") # Shut down engines my_engine.quit() opp_engine.quit() # Summary print("\n===== FINAL SCORE =====") print(f"Wins: {scores['win']}") print(f"Draws: {scores['draw']}") print(f"Losses: {scores['loss']}") print("=======================") score = scores["win"] + 0.5 * scores["draw"] print(f"Score: {score}/{GAMES}") print("=======================") if __name__ == "__main__": main()