diff --git a/chesspp/engine.py b/chesspp/engine.py index d5c606d..8205435 100644 --- a/chesspp/engine.py +++ b/chesspp/engine.py @@ -94,7 +94,7 @@ class BayesMctsEngine(Engine): def play(self, board: chess.Board, limit: Limit) -> chess.engine.PlayResult: if len(board.move_stack) != 0: # apply previous move to mcts --> reuse previous simulation results self.mcts.apply_move(board.peek()) - self.mcts.sample() + limit.run(lambda: self.mcts.sample(1)) # limit.run(lambda: mcts_root.build_tree()) best_move = max(self.mcts.get_moves().items(), key=lambda x: x[1])[0] if board.turn == chess.WHITE else ( min(self.mcts.get_moves().items(), key=lambda x: x[1])[0]) diff --git a/chesspp/simulation.py b/chesspp/simulation.py index 4637f63..b7b1d33 100644 --- a/chesspp/simulation.py +++ b/chesspp/simulation.py @@ -24,9 +24,6 @@ class EvaluationResult: def simulate_game(white: Engine, black: Engine, limit: Limit, board: chess.Board) -> chess.pgn.Game: is_white_playing = True while not board.is_game_over(): - print("simulation board:\n", board) - print() - print("mcts board:\n", white.mcts.board) play_result = white.play(board, limit) if is_white_playing else black.play(board, limit) board.push(play_result.move) is_white_playing = not is_white_playing @@ -38,26 +35,31 @@ def simulate_game(white: Engine, black: Engine, limit: Limit, board: chess.Board class Evaluation: - def __init__(self, engine_a: Engine.__class__, engine_b: Engine.__class__, limit: Limit): + def __init__(self, engine_a: Engine.__class__, strategy_a, engine_b: Engine.__class__, strategy_b, limit: Limit): self.engine_a = engine_a + self.strategy_a = strategy_a self.engine_b = engine_b + self.strategy_b = strategy_b self.limit = limit def run(self, n_games=100) -> List[EvaluationResult]: with mp.Pool(mp.cpu_count()) as pool: - args = [(self.engine_a, self.engine_b, self.limit) for i in range(n_games)] + 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) @staticmethod def _test_simulate(arg: Tuple[Engine.__class__, Engine.__class__, Limit]) -> EvaluationResult: - engine_a, engine_b, limit = arg + engine_a, strategy_a, engine_b, strategy_b, limit = arg flip_engines = bool(random.getrandbits(1)) - if flip_engines: - black, white = engine_a(chess.BLACK), engine_b(chess.WHITE) - else: - white, black = engine_a(chess.WHITE), engine_b(chess.BLACK) - game = simulate_game(white, black, limit) + board = chess.Board() + + if flip_engines: + black, white = engine_a(board.copy(), chess.BLACK, strategy_a), engine_b(board.copy(), chess.WHITE, strategy_b) + else: + white, black = engine_a(board.copy(), chess.WHITE, strategy_a), engine_b(board.copy(), chess.BLACK, strategy_b) + + game = simulate_game(white, black, limit, board) winner = game.end().board().outcome().winner result = Winner.Draw diff --git a/chesspp/stockfish_strategy.py b/chesspp/stockfish_strategy.py index 270c7e4..82ddaf3 100644 --- a/chesspp/stockfish_strategy.py +++ b/chesspp/stockfish_strategy.py @@ -1,14 +1,25 @@ +import os import chess from chesspp.i_strategy import IStrategy import chess.engine +_DIR = os.path.abspath(os.path.dirname(__file__)) class StockFishStrategy(IStrategy): - stockfish: chess.engine.SimpleEngine def __init__(self): - self.stockfish = chess.engine.SimpleEngine.popen_uci( - "/home/luke/projects/pp-project/chess-engine-pp/stockfish/stockfish-ubuntu-x86-64-avx2") + self._stockfish = None + + @property + 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")) + return self._stockfish + + @stockfish.setter + def stockfish(self, stockfish): + self._stockfish = stockfish def pick_next_move(self, board: chess.Board) -> chess.Move | None: move = self.stockfish.play(board, chess.engine.Limit(depth=4)).move diff --git a/chesspp/web.py b/chesspp/web.py index 0c29cf6..a1a5608 100644 --- a/chesspp/web.py +++ b/chesspp/web.py @@ -75,8 +75,8 @@ class WebInterface: async def turns(): """ Simulates the game and sends the response to the client """ - runner = Simulate(self.white(chess.Board(), chess.WHITE, RandomStrategy(random.Random())), self.black( - chess.Board(), chess.BLACK, RandomStrategy(random.Random()))).run(limit) + runner = Simulate(self.white(chess.Board(), chess.WHITE, StockFishStrategy()), self.black( + chess.Board(), chess.BLACK, StockFishStrategy())).run(self.limit) def sim(): return next(runner, None) @@ -103,6 +103,6 @@ class WebInterface: ]) web.run_app(app) -if __name__ == '__main__': +def run_sample(): limit = engine.Limit(time=0.5) WebInterface(engine.BayesMctsEngine, engine.ClassicMctsEngine, limit).run_app() diff --git a/main.py b/main.py index db144c3..b93bf13 100644 --- a/main.py +++ b/main.py @@ -80,11 +80,11 @@ def analyze_results(moves: dict): def test_evaluation(): - a = engine.ClassicMctsEngine - b = engine.RandomEngine + a = engine.BayesMctsEngine + b = engine.ClassicMctsEngine limit = engine.Limit(time=0.5) - evaluator = simulation.Evaluation(a, b, limit) - results = evaluator.run(1) + evaluator = simulation.Evaluation(a, StockFishStrategy(), b, RandomStrategy(random.Random()), limit) + results = evaluator.run(2) 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 @@ -95,8 +95,8 @@ def test_evaluation(): def main(): - # test_evaluation() - test_simulate() + test_evaluation() + #test_simulate() # test_mcts() # test_stockfish() # test_stockfish_prob()