diff --git a/chesspp/simulation.py b/chesspp/simulation.py index 3662f4f..30ae071 100644 --- a/chesspp/simulation.py +++ b/chesspp/simulation.py @@ -43,8 +43,9 @@ class Evaluation: self.strategy_b = strategy_b self.limit = limit - def run(self, n_games=100) -> List[EvaluationResult]: - with mp.Pool(mp.cpu_count()) as pool: + def run(self, n_games=100, proc=mp.cpu_count()) -> List[EvaluationResult]: + proc = min(proc, mp.cpu_count()) + with mp.Pool(proc) as pool: args = [(self.engine_a, self.strategy_a, self.engine_b, self.strategy_b, self.limit) for i in range(n_games)] return pool.map(Evaluation._test_simulate, args) diff --git a/chesspp/stockfish_strategy.py b/chesspp/stockfish_strategy.py index 4485987..4ae3024 100644 --- a/chesspp/stockfish_strategy.py +++ b/chesspp/stockfish_strategy.py @@ -9,8 +9,9 @@ _DIR = os.path.abspath(os.path.dirname(__file__)) class StockFishStrategy(IStrategy): - def __init__(self): + def __init__(self, path="../stockfish/stockfish-windows-x86-64-avx2"): self._stockfish = None + self.path = path def __del__(self): if self._stockfish is not None: @@ -20,7 +21,7 @@ class StockFishStrategy(IStrategy): def stockfish(self) -> chess.engine.SimpleEngine: if self._stockfish is None: self._stockfish = self.stockfish = chess.engine.SimpleEngine.popen_uci( - os.path.join(_DIR, "../stockfish/stockfish-ubuntu-x86-64-avx2")) + os.path.join(_DIR, self.path)) return self._stockfish @stockfish.setter diff --git a/main.py b/main.py index b890209..619c532 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,6 @@ import random +import time + import chess import chess.engine import chess.pgn @@ -9,6 +11,8 @@ from chesspp.stockfish_strategy import StockFishStrategy from chesspp import engine from chesspp import util from chesspp import simulation, eval +import argparse +import os def test_simulate(): @@ -37,7 +41,10 @@ def test_bayes_mcts(): seed = None strategy = RandomStrategy(random.Random(seed)) mcts = BayesianMcts(board, strategy, chess.BLACK, seed) - mcts.sample() + t1 = time.time_ns() + mcts.sample(1) + t2 = time.time_ns() + print ((t2 - t1)/1e6) mcts.print() for move, score in mcts.get_moves().items(): print("move (mcts):", move, " with score:", score) @@ -80,11 +87,20 @@ def analyze_results(moves: dict): def test_evaluation(): - a = engine.BayesMctsEngine - b = engine.ClassicMctsEngine - limit = engine.Limit(time=0.5) - evaluator = simulation.Evaluation(a, StockFishStrategy(), b, StockFishStrategy(), limit) - results = evaluator.run(24) + a, b, s1, s2, n, limit, stockfish_path, proc = read_arguments() + limit = engine.Limit(time=limit) + if s1 == StockFishStrategy: + strat1 = StockFishStrategy(stockfish_path) + else: + strat1 = s1() + + if s2 == StockFishStrategy: + strat2 = StockFishStrategy(stockfish_path) + else: + strat2 = s1() + + evaluator = simulation.Evaluation(a, strat1, b, strat2, limit) + results = evaluator.run(n, proc) a_results = len(list(filter(lambda x: x.winner == simulation.Winner.Engine_A, results))) / len(results) * 100 b_results = len(list(filter(lambda x: x.winner == simulation.Winner.Engine_B, results))) / len(results) * 100 draws = len(list(filter(lambda x: x.winner == simulation.Winner.Draw, results))) / len(results) * 100 @@ -94,6 +110,43 @@ def test_evaluation(): print(f"{draws}% of games resulted in a draw") +def read_arguments(): + parser = argparse.ArgumentParser( + prog='EvaluateEngine', + description='Compare two engines by playing multiple games against each other' + ) + + engines = {"Classic": engine.ClassicMctsEngine, "Baysian": engine.BayesMctsEngine, "Random": engine.RandomEngine} + strategies = {"Random": RandomStrategy, "Stockfish": StockFishStrategy} + + if os.name == 'nt': + stockfish_default = "../stockfish/stockfish-windows-x86-64-avx2" + else: + stockfish_default = "../stockfish/stockfish-ubuntu-x86-64-avx2" + + parser.add_argument("--proc", default=2, help="Number of processors to use for simulation, default=1") + parser.add_argument("--time", default=0.5, help="Time limit for each simulation step, default=0.5") + parser.add_argument("-n", default=100, help="Number of games to simulate, default=100") + parser.add_argument("--stockfish", default=stockfish_default, + help=f"Path for stockfish executable, default='{stockfish_default}'") + parser.add_argument("--engine1", "--e1", help="Engine A for the simulation", choices=engines.keys(), required=True) + parser.add_argument("--engine2", "--e2", help="Engine B for the simulation", choices=engines.keys(), required=True) + parser.add_argument("--strategy1", "--s1", default=list(strategies.keys())[0], + help="Strategy for engine A for the rollout", + choices=strategies.keys()) + parser.add_argument("--strategy2", "--s2", default=list(strategies.keys())[0], + help="Strategy for engine B for the rollout", + choices=strategies) + args = parser.parse_args() + + engine1 = engines[args.engine1] + engine2 = engines[args.engine2] + strategy1 = strategies[args.strategy1] + strategy2 = strategies[args.strategy2] + + return engine1, engine2, strategy1, strategy2, int(args.n), float(args.time), args.stockfish, int(args.proc) + + def main(): test_evaluation() # test_simulate()