Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 35 additions & 31 deletions moonfish/engines/l1p_alpha_beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
119 changes: 60 additions & 59 deletions moonfish/engines/l2p_alpha_beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
49 changes: 25 additions & 24 deletions moonfish/engines/lazy_smp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
2 changes: 1 addition & 1 deletion moonfish/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down