diff --git a/moonfish/engines/l1p_alpha_beta.py b/moonfish/engines/l1p_alpha_beta.py index f2620e8..a0d9ba0 100644 --- a/moonfish/engines/l1p_alpha_beta.py +++ b/moonfish/engines/l1p_alpha_beta.py @@ -11,37 +11,41 @@ class Layer1ParallelAlphaBeta(AlphaBeta): """ def search_move(self, board: Board) -> Move: + self.nodes = 0 # start multiprocessing nprocs = cpu_count() - pool = Pool(processes=nprocs) - manager = Manager() - shared_cache = manager.dict() - - # creating list of moves at layer 1 - moves = list(board.legal_moves) - arguments = [] - for move in moves: - board.push(move) - arguments.append( - ( - board.copy(), - self.config.negamax_depth - 1, - self.config.null_move, - shared_cache, + + with Pool(processes=nprocs) as pool, Manager() as manager: + shared_cache = manager.dict() + + # creating list of moves at layer 1 + moves = list(board.legal_moves) + arguments = [] + for move in moves: + board.push(move) + arguments.append( + ( + board.copy(), + self.config.negamax_depth - 1, + self.config.null_move, + shared_cache, + ) ) - ) - board.pop() - - # executing all the moves at layer 1 in parallel - # starmap blocks until all process are done - processes = pool.starmap(self.negamax, arguments) - results = [] - - # inserting move information in the results - for i in range(len(processes)): - results.append((*processes[i], moves[i])) - - # sorting results and getting best move - results.sort(key=lambda a: a[0]) - best_move = results[0][2] - return best_move + board.pop() + + # executing all the moves at layer 1 in parallel + # starmap blocks until all processes are done + processes = pool.starmap(self.negamax, arguments) + results = [] + + # inserting move information in the results + # negamax returns (score, best_move) - we negate score since + # it's from opponent's perspective + for i in range(len(processes)): + score = -processes[i][0] # Negate: opponent's -> our perspective + results.append((score, processes[i][1], moves[i])) + + # sorting results by score (descending) and getting best move + results.sort(key=lambda a: a[0], reverse=True) + best_move = results[0][2] + return best_move diff --git a/moonfish/engines/l2p_alpha_beta.py b/moonfish/engines/l2p_alpha_beta.py index 010b8f8..b4e7451 100644 --- a/moonfish/engines/l2p_alpha_beta.py +++ b/moonfish/engines/l2p_alpha_beta.py @@ -74,68 +74,69 @@ def generate_board_and_moves( return boards_and_moves def search_move(self, board: Board) -> Move: + self.nodes = 0 START_LAYER = 2 # start multiprocessing nprocs = cpu_count() - pool = Pool(processes=nprocs) - manager = Manager() - shared_cache = manager.dict() - # pointer that help us in finding the best next move - board_to_move_that_generates_it = manager.dict() + with Pool(processes=nprocs) as pool, Manager() as manager: + shared_cache = manager.dict() + + # pointer that help us in finding the best next move + board_to_move_that_generates_it = manager.dict() + + # starting board list + board_list = [(board, board, 0)] + + # generating all possible boards for up to 2 moves ahead + for _ in range(START_LAYER): + arguments = [ + (board, board_to_move_that_generates_it, layer) + for board, _, layer in board_list + ] + processes = pool.starmap(self.generate_board_and_moves, arguments) + board_list = [board for board in sum(processes, [])] + + negamax_arguments = [ + ( + board, + self.config.negamax_depth - START_LAYER, + self.config.null_move, + shared_cache, + ) + for board, _, _ in board_list + ] - # starting board list - board_list = [(board, board, 0)] + parallel_layer_result = pool.starmap(self.negamax, negamax_arguments) - # generating all possible boards for up to 2 moves ahead - for _ in range(START_LAYER): - arguments = [ - (board, board_to_move_that_generates_it, layer) - for board, _, layer in board_list - ] - processes = pool.starmap(self.generate_board_and_moves, arguments) - board_list = [board for board in sum(processes, [])] - - negamax_arguments = [ - ( - board, - self.config.negamax_depth - START_LAYER, - self.config.null_move, - shared_cache, - ) - for board, _, _ in board_list - ] - - parallel_layer_result = pool.starmap(self.negamax, negamax_arguments) - - # grouping output based on the board that generates it - groups = defaultdict(list) - - # adding information about the board and layer - # that generates the results and separating them - # into groups based on the root board - for i in range(len(parallel_layer_result)): - groups[board_list[i][1].fen()].append( - (*parallel_layer_result[i], board_list[i][0], board_list[i][2]) - ) - - best_boards = [] - - for group in groups.values(): - # layer and checkmate corrections - # they are needed to adjust for - # boards from different layers - group = list(map(LAYER_SIGNAL_CORRECTION, group)) - group = list(map(self.checkmate_correction, group)) - # get best move from group - group.sort(key=lambda a: a[0]) - best_boards.append(group[0]) - - # get best board - best_boards.sort(key=lambda a: a[0], reverse=True) - best_board = best_boards[0][2].fen() - - # get move that results in best board - best_move = board_to_move_that_generates_it[best_board] - - return best_move + # grouping output based on the board that generates it + groups = defaultdict(list) + + # adding information about the board and layer + # that generates the results and separating them + # into groups based on the root board + for i in range(len(parallel_layer_result)): + groups[board_list[i][1].fen()].append( + (*parallel_layer_result[i], board_list[i][0], board_list[i][2]) + ) + + best_boards = [] + + for group in groups.values(): + # layer and checkmate corrections + # they are needed to adjust for + # boards from different layers + group = list(map(LAYER_SIGNAL_CORRECTION, group)) + group = list(map(self.checkmate_correction, group)) + # get best move from group + group.sort(key=lambda a: a[0]) + best_boards.append(group[0]) + + # get best board + best_boards.sort(key=lambda a: a[0], reverse=True) + best_board = best_boards[0][2].fen() + + # get move that results in best board + best_move = board_to_move_that_generates_it[best_board] + + return best_move diff --git a/moonfish/engines/lazy_smp.py b/moonfish/engines/lazy_smp.py index 315c282..229d2cc 100644 --- a/moonfish/engines/lazy_smp.py +++ b/moonfish/engines/lazy_smp.py @@ -7,33 +7,34 @@ class LazySMP(AlphaBeta): def search_move(self, board: Board) -> Move: + self.nodes = 0 # start multiprocessing nprocs = cpu_count() - pool = Pool(processes=nprocs) - manager = Manager() - shared_cache = manager.dict() - # executing all the moves at layer 1 in parallel - # starmap blocks until all process are done - pool.starmap( - self.negamax, - [ + with Pool(processes=nprocs) as pool, Manager() as manager: + shared_cache = manager.dict() + # executing negamax in parallel N times + # all processes share the cache for faster convergence + # starmap blocks until all processes are done + pool.starmap( + self.negamax, + [ + ( + board, + self.config.negamax_depth, + self.config.null_move, + shared_cache, + ) + for _ in range(nprocs) + ], + ) + + # return best move for our original board + return shared_cache[ ( - board, + board._transposition_key(), self.config.negamax_depth, self.config.null_move, - shared_cache, + NEG_INF, + INF, ) - for _ in range(nprocs) - ], - ) - - # return best move for our original board - return shared_cache[ - ( - board._transposition_key(), - self.config.negamax_depth, - self.config.null_move, - NEG_INF, - INF, - ) - ][1] + ][1] diff --git a/moonfish/main.py b/moonfish/main.py index a2a36cf..32f1e50 100644 --- a/moonfish/main.py +++ b/moonfish/main.py @@ -39,7 +39,7 @@ def run(config: Config): "--null-move", type=bool, help="If True, use null move prunning.", - default=False, + default=True, ) @click.option( "--null-move-r",