From 9a4febaaf40a9e19185307ff4463aaf43cf6b839 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Sun, 17 Dec 2023 22:16:43 +0100 Subject: [PATCH 01/18] Rework Heuristics --- src/classes/Heuristic.py | 62 ++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/classes/Heuristic.py b/src/classes/Heuristic.py index d7fa3ea..2656180 100644 --- a/src/classes/Heuristic.py +++ b/src/classes/Heuristic.py @@ -17,28 +17,41 @@ class ScoreHeuristicEngine(HeuristicEngine): class WeightHeuristicEngine(HeuristicEngine): + def __init__(self, logger, options): + super().__init__(logger, options) + self.weights = self._get_weight_array() + self.logger.debug("{}".format(self.show_weights())) + def get(self, board, player): score = self.get_weight(board, player) return score def get_weight(self, board, player): score = 0 - size = board.get_board_size() - weights = self._get_weight_array(size) - for pos_x in range(size): - for pos_y in range(size): - if board._board[pos_x][pos_y] == player: - score += weights[pos_x][pos_y] - else: - score -= weights[pos_x][pos_y] + size = self.options['size'] + w = [[ 0 for _ in range(size)] for _ in range(size)] + for pos_x in range(self.options['size']): + for pos_y in range(self.options['size']): + p = board._board[pos_x][pos_y] + if p == player: + score += self.weights[pos_x][pos_y] + w[pos_x][pos_y] = self.weights[pos_x][pos_y] + + elif p != player and p != board._EMPTY: + score -= self.weights[pos_x][pos_y] + w[pos_x][pos_y] = -self.weights[pos_x][pos_y] return score - def _get_weight_array(self, size): + def _get_weight_array(self): + size = self.options['size'] w = [[ 0 for _ in range(size)] for _ in range(size)] padding = size // 5 center = size // 2 - for pos_y in range(size): - for pos_x in range(size): + full_range = range(self.options['size']) + center_range = range(center - padding, center + padding) + + for pos_y in full_range: + for pos_x in full_range: # Elements in the corner if pos_x in [0, size -1] and pos_y in [0,size - 1]: @@ -49,10 +62,35 @@ class WeightHeuristicEngine(HeuristicEngine): w[pos_x][pos_y] = self.options['weight'][1] # Element the center - elif pos_x in range( center - padding, center + padding) and pos_y in range(center - padding, center + padding): + elif pos_x in center_range and pos_y in center_range: w[pos_x][pos_y] = self.options['weight'][0] return w + + def show_weights(self): + display = "\n |" + for x in range(self.options['size']): + display += "{:^3}|".format(x) + display += "\n" + for x in range(self.options['size']): + display += "{:^3}|".format(str(x)) + for y in range(self.options['size']): + display += "{:^3}|".format(self.weights[x][y]) + display += "\n" + return display + + @staticmethod + def show_weight_score(weights, size): + display = "\n |" + for x in range(size): + display += "{:^3}|".format(x) + display += "\n" + for x in range(size): + display += "{:^3}|".format(str(x)) + for y in range(size): + display += "{:^3}|".format(weights[x][y]) + display += "\n" + return display class FullHeuristicEngine(WeightHeuristicEngine): def get(self, board, player): From 55f2a29084daf4207230c14d8777f56919a74c6e Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Sun, 17 Dec 2023 22:17:50 +0100 Subject: [PATCH 02/18] Instnciate Heuristics with right parameters --- src/game.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game.py b/src/game.py index 6f60705..82df118 100755 --- a/src/game.py +++ b/src/game.py @@ -113,7 +113,8 @@ if __name__ == '__main__': logger, heuristic_engine[args.white_heuristic_engine]( logger, { - 'weight': args.weight + 'weight': args.weight, + 'size': game.get_board_size() } ), { @@ -126,7 +127,8 @@ if __name__ == '__main__': logger, heuristic_engine[args.black_heuristic_engine]( logger, { - 'weight': args.weight + 'weight': args.weight, + 'size': game.get_board_size() } ), { From 8074175ad3a2c289cd3ccace2c6f62bb3ead3a67 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Sun, 17 Dec 2023 22:18:24 +0100 Subject: [PATCH 03/18] Remove Iterative Deepening garbage --- src/classes/Engines.py | 62 ++++-------------------------------------- 1 file changed, 5 insertions(+), 57 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index 4ad9d13..dd129c9 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -60,8 +60,11 @@ class HumanPlayerEngine(PlayerEngine): return [board._nextPlayer, x, y] class MinmaxPlayerEngine(PlayerEngine): + def get_move(self, board): super().get_move(board) + + def get_best_move(board): value = -math.inf nodes = 1 leafs = 0 @@ -85,12 +88,11 @@ class MinmaxPlayerEngine(PlayerEngine): leafs )) return move - def checkMinMax(self, board, friend_move:bool, depth :int = 2): nodes = 1 leafs = 0 move = '' - if depth == 0: + if depth == 0 or board.is_game_over(): leafs +=1 return self.heuristic.get(board, self.player), nodes, leafs @@ -152,7 +154,7 @@ class AlphabetaPlayerEngine(PlayerEngine): def checkAlphaBeta(self, board, friend_move : bool, depth, alpha, beta): nodes = 1 leafs = 0 - if depth == 0 : + if depth == 0 or board.is_game_over(): leafs +=1 return self.heuristic.get(board, self.player), nodes, leafs @@ -190,57 +192,3 @@ class AlphabetaPlayerEngine(PlayerEngine): return alpha, nodes, leafs return beta, nodes, leafs -class MinmaxDeepeningPlayerEngine(PlayerEngine): - - def get_move(self, board): - super().get_move(board) - value = -math.inf - nodes = 1 - leafs = 0 - move = '' - start_time = time.time() - for m in board.legal_moves(): - board.push(m) - v, n, l = self.checkMinMax(board, False, start_time) - if v > value: - value = v - move = m - self.logger.debug("found a better move: {} (heuristic:{})".format( - move, - value - )) - nodes += n - leafs += l - board.pop() - return move - - def checkMinMax(self, board, friend_move:bool, start_time): - nodes = 1 - leafs = 0 - move = '' - if time.time() >= start_time + self.options['time_limit'] or board.is_game_over(): - leafs +=1 - return self.heuristic.get(board, self.player), nodes, leafs - - if friend_move: - value = -math.inf - for m in board.legal_moves(): - board.push(m) - v, n, l = self.checkMinMax(board, False, start_time) - if v > value: - value = v - nodes += n - leafs += l - board.pop() - - else: - value = math.inf - for m in board.legal_moves(): - board.push(m) - v, n, l = self.checkMinMax(board, True, start_time) - if v < value: - value = v - board.pop(); - nodes += n - leafs += l - return value, nodes, leafs From 2ffd077a262b6403398b776cd5af2b5fdc8ff5b4 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Mon, 18 Dec 2023 12:07:51 +0100 Subject: [PATCH 04/18] Implement Iterative Deepening Minmax --- src/classes/Engines.py | 52 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index dd129c9..8b29dca 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -1,4 +1,4 @@ -import random, math, time +import random, math, time, signal class PlayerEngine: def __init__(self, player, logger, heuristic, options: dict = {}): @@ -7,6 +7,7 @@ class PlayerEngine: self.logger = logger self.heuristic = heuristic self.options = options + self.interrupt_search = False self.logger.info("Init engine {}, options:{}".format( self.__class__.__name__, self.options @@ -92,7 +93,7 @@ class MinmaxPlayerEngine(PlayerEngine): nodes = 1 leafs = 0 move = '' - if depth == 0 or board.is_game_over(): + if depth == 0 or board.is_game_over() or self.interrupt_search: leafs +=1 return self.heuristic.get(board, self.player), nodes, leafs @@ -192,3 +193,50 @@ class AlphabetaPlayerEngine(PlayerEngine): return alpha, nodes, leafs return beta, nodes, leafs + +class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): + + def get_move(self, board): + super().get_move(board) + self.interrupt_search = False + + # Get an alarm signal to stop iterations + signal.signal(signal.SIGALRM, self.alarm_handler) + signal.alarm(self.options['time_limit']) + depth = 1 + value = -math.inf + nodes = 1 + leafs = 0 + move = None + + # We can go deeper than blank place in our board, then we must get + # numbers of avaible place + max_depth = (board.get_board_size()**2) - ( + board.get_nb_pieces()[0] + board.get_nb_pieces()[1]) + + # Iterate depth while our alarm does not trigger and there is enougth + # avaiable move to play + while not self.interrupt_search and depth <= max_depth: + for m in board.legal_moves(): + board.push(m) + v, n, l = self.checkMinMax(board, False, depth - 1) + if v > value: + value = v + move = m + self.logger.debug("found a better move: {} (heuristic:{})".format( + move, + value + )) + nodes += n + leafs += l + board.pop() + depth = depth + 1 + self.logger.debug("id_minmax - depth reached: {} | max depth : {}".format( + depth - 1, + max_depth + )) + return move + + def alarm_handler(self, signal, frame): + self.logger.debug("Raise SIGALMR Signal") + self.interrupt_search = True From aa9d13d587433f1b2a38f18671d325c6956eebde Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Tue, 19 Dec 2023 22:02:55 +0100 Subject: [PATCH 05/18] First working version of iterative deepening alpha beta --- src/classes/Engines.py | 68 ++++++++++++++++++++++++++++++++++++------ src/game.py | 5 ++-- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index 8b29dca..6ba13f6 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -155,7 +155,7 @@ class AlphabetaPlayerEngine(PlayerEngine): def checkAlphaBeta(self, board, friend_move : bool, depth, alpha, beta): nodes = 1 leafs = 0 - if depth == 0 or board.is_game_over(): + if depth == 0 or board.is_game_over() or self.interrupt_search: leafs +=1 return self.heuristic.get(board, self.player), nodes, leafs @@ -169,10 +169,10 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes += n leafs += l if alpha >= beta: - self.logger.debug("Alpha pruning - alpha:{} / beta:{}".format( - alpha, - beta - )) + # self.logger.debug("Alpha pruning - alpha:{} / beta:{}".format( + # alpha, + # beta + # )) return beta, nodes, leafs return alpha, nodes, leafs @@ -186,10 +186,10 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes += n leafs += l if alpha >= beta: - self.logger.debug("Beta pruning - alpha:{} / beta:{}".format( - alpha, - beta - )) + # self.logger.debug("Beta pruning - alpha:{} / beta:{}".format( + # alpha, + # beta + # )) return alpha, nodes, leafs return beta, nodes, leafs @@ -240,3 +240,53 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): def alarm_handler(self, signal, frame): self.logger.debug("Raise SIGALMR Signal") self.interrupt_search = True + + + +class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): + + def get_move(self, board): + super().get_move(board) + self.interrupt_search = False + + # Get an alarm signal to stop iterations + signal.signal(signal.SIGALRM, self.alarm_handler) + signal.alarm(self.options['time_limit']) + depth = 1 + alpha = -math.inf + beta = math.inf + nodes = 1 + leafs = 0 + move = None + + # We can go deeper than blank place in our board, then we must get + # numbers of avaible place + max_depth = (board.get_board_size()**2) - ( + board.get_nb_pieces()[0] + board.get_nb_pieces()[1]) + + # Iterate depth while our alarm does not trigger and there is enougth + # avaiable move to play + while not self.interrupt_search and depth <= max_depth: + for m in board.legal_moves(): + board.push(m) + v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) + board.pop() + nodes += n + leafs += l + if v >= alpha: + alpha = v + move = m + self.logger.debug("found a better move: {} (heuristic:{})".format( + move, + alpha + )) + depth = depth + 1 + self.logger.debug("id_alphabeta - depth reached: {} | max depth : {}".format( + depth - 1, + max_depth + )) + return move + + def alarm_handler(self, signal, frame): + self.logger.debug("Raise SIGALMR Signal") + self.interrupt_search = True diff --git a/src/game.py b/src/game.py index 82df118..966f832 100755 --- a/src/game.py +++ b/src/game.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from classes.Reversi import Board -from classes.Engines import RandomPlayerEngine, HumanPlayerEngine, MinmaxPlayerEngine, AlphabetaPlayerEngine, MinmaxDeepeningPlayerEngine +from classes.Engines import RandomPlayerEngine, HumanPlayerEngine, MinmaxPlayerEngine, AlphabetaPlayerEngine, MinmaxDeepeningPlayerEngine, AlphaBetaDeepeningPlayerEngine from classes.Heuristic import ScoreHeuristicEngine, WeightHeuristicEngine, FullHeuristicEngine import logging as log import argparse as arg @@ -12,7 +12,7 @@ from classes.CustomFormater import CustomFormatter Function to parse command line arguments """ def parse_aguments(): - engines_choices=['random', 'human', 'minmax', 'alphabeta', 'id_minmax'] + engines_choices=['random', 'human', 'minmax', 'alphabeta', 'id_minmax', 'id_alphabeta'] heuristic_choices=['score', 'weight', 'full'] parser = arg.ArgumentParser('Playing Reversi with (virtual) friend') @@ -79,6 +79,7 @@ if __name__ == '__main__': "minmax": MinmaxPlayerEngine, "alphabeta": AlphabetaPlayerEngine, "id_minmax": MinmaxDeepeningPlayerEngine, + "id_alphabeta": AlphaBetaDeepeningPlayerEngine } heuristic_engine = { "score": ScoreHeuristicEngine, From 46e83a63ce9a4a80972074d4aff8dd0d8e94c83d Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 01:14:53 +0100 Subject: [PATCH 06/18] Rework alphabeta function --- src/classes/Engines.py | 52 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index 6ba13f6..242c41f 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -64,8 +64,6 @@ class MinmaxPlayerEngine(PlayerEngine): def get_move(self, board): super().get_move(board) - - def get_best_move(board): value = -math.inf nodes = 1 leafs = 0 @@ -124,30 +122,32 @@ class AlphabetaPlayerEngine(PlayerEngine): def get_move(self, board): super().get_move(board) + self.logger.debug("Enter AlphaBeta function") alpha = -math.inf beta = math.inf nodes = 1 leafs = 0 move = [] - value = -math.inf - for m in board.legal_moves(): + all_moves = board.legal_moves() + # random.shuffle(all_moves) + for m in all_moves: board.push(m) - v, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta) + value, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta) board.pop() - alpha = max(alpha,v) nodes += n leafs += l - if alpha >= value: - value = alpha + if value >= alpha: + alpha = value move = m - self.logger.debug("found a better move: {} (heuristic:{})".format( + self.logger.debug("\t-> found a better move: {} | heuristic:{})".format( move, alpha )) - self.logger.debug("Tree statistics:\n\tnodes:{}\n\tleafs:{}".format( + self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( nodes, - leafs + leafs, + alpha )) return move @@ -160,36 +160,38 @@ class AlphabetaPlayerEngine(PlayerEngine): return self.heuristic.get(board, self.player), nodes, leafs if friend_move: - value = -math.inf - for m in board.legal_moves(): + all_moves = board.legal_moves() + random.shuffle(all_moves) + for m in all_moves: board.push(m) v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) board.pop() - alpha = max(value,v) + alpha = max(alpha,v) nodes += n leafs += l if alpha >= beta: - # self.logger.debug("Alpha pruning - alpha:{} / beta:{}".format( - # alpha, - # beta - # )) + self.logger.debug("\t - Beta pruning - alpha:{} / beta:{}".format( + alpha, + beta + )) return beta, nodes, leafs return alpha, nodes, leafs else: - value = math.inf - for m in board.legal_moves(): + all_moves = board.legal_moves() + random.shuffle(all_moves) + for m in all_moves: board.push(m) v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta) board.pop(); - beta = min(beta,v) + beta = min(beta, v) nodes += n leafs += l if alpha >= beta: - # self.logger.debug("Beta pruning - alpha:{} / beta:{}".format( - # alpha, - # beta - # )) + self.logger.debug("\t - Alpha pruning | alpha:{} | beta:{}".format( + alpha, + beta + )) return alpha, nodes, leafs return beta, nodes, leafs From 5dbf82521db9f9659a069a221aa5b222ba44d755 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 01:35:42 +0100 Subject: [PATCH 07/18] Change displayed informations --- src/classes/Engines.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index 242c41f..ac3b421 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -67,14 +67,14 @@ class MinmaxPlayerEngine(PlayerEngine): value = -math.inf nodes = 1 leafs = 0 - move = '' + move = [] for m in board.legal_moves(): board.push(m) v, n, l = self.checkMinMax(board, False, self.options['depth'] - 1) if v > value: value = v move = m - self.logger.debug("found a better move: {} (heuristic:{})".format( + self.logger.debug("\tfound a better move: {} (heuristic:{})".format( move, value )) @@ -82,15 +82,17 @@ class MinmaxPlayerEngine(PlayerEngine): leafs += l board.pop() - self.logger.debug("Tree statistics:\n\tnodes:{}\n\tleafs:{}".format( + self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( nodes, - leafs - )) + leafs, + value + )) return move + def checkMinMax(self, board, friend_move:bool, depth :int = 2): nodes = 1 leafs = 0 - move = '' + move = [] if depth == 0 or board.is_game_over() or self.interrupt_search: leafs +=1 return self.heuristic.get(board, self.player), nodes, leafs @@ -129,7 +131,6 @@ class AlphabetaPlayerEngine(PlayerEngine): leafs = 0 move = [] all_moves = board.legal_moves() - # random.shuffle(all_moves) for m in all_moves: board.push(m) value, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta) @@ -161,7 +162,6 @@ class AlphabetaPlayerEngine(PlayerEngine): if friend_move: all_moves = board.legal_moves() - random.shuffle(all_moves) for m in all_moves: board.push(m) v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) @@ -179,7 +179,6 @@ class AlphabetaPlayerEngine(PlayerEngine): else: all_moves = board.legal_moves() - random.shuffle(all_moves) for m in all_moves: board.push(m) v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta) From 9c541c90eabb29b319562f3fba65e99b3aed8d83 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 18:15:13 +0100 Subject: [PATCH 08/18] Remove useless infomations in formatter --- src/classes/CustomFormater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/CustomFormater.py b/src/classes/CustomFormater.py index 02ad065..ac2926f 100644 --- a/src/classes/CustomFormater.py +++ b/src/classes/CustomFormater.py @@ -8,7 +8,7 @@ class CustomFormatter(logging.Formatter): red = "\x1b[31;20m" bold_red = "\x1b[31;1m" reset = "\x1b[0m" - format = "%(levelname)s: %(message)s (%(filename)s:%(lineno)d)" + format = "%(levelname)s: %(message)s" FORMATS = { logging.DEBUG: blue + format + reset, From 935d3b8f23971479903ad5ca9afc324263dd9388 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 18:24:55 +0100 Subject: [PATCH 09/18] Fix condition in get_player_name() --- src/classes/Engines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index ac3b421..e833692 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -21,7 +21,7 @@ class PlayerEngine: @staticmethod def get_player_name(player): - return 'White (O)' if player is 2 else 'Black (X)' + return 'White (O)' if player == 2 else 'Black (X)' class RandomPlayerEngine(PlayerEngine): def get_move(self, board): From 6979749d5d788902e8c0cbdb3ce1b4de99f3ddc2 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 18:25:55 +0100 Subject: [PATCH 10/18] Create a function to give moves It's possible to randomize it now --- src/classes/Engines.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index e833692..534699f 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -8,6 +8,7 @@ class PlayerEngine: self.heuristic = heuristic self.options = options self.interrupt_search = False + self.randomize_moves = False self.logger.info("Init engine {}, options:{}".format( self.__class__.__name__, self.options @@ -18,6 +19,12 @@ class PlayerEngine: self.__class__.__name__, self.get_player_name(self.player) )) + + def get_player_moves(self, board): + if self.randomize_moves is True: + return random.random(board.legal_moves()) + else: + return board.legal_moves() @staticmethod def get_player_name(player): @@ -68,7 +75,7 @@ class MinmaxPlayerEngine(PlayerEngine): nodes = 1 leafs = 0 move = [] - for m in board.legal_moves(): + for m in self.get_player_moves(board): board.push(m) v, n, l = self.checkMinMax(board, False, self.options['depth'] - 1) if v > value: @@ -99,7 +106,7 @@ class MinmaxPlayerEngine(PlayerEngine): if friend_move: value = -math.inf - for m in board.legal_moves(): + for m in self.get_player_moves(board): board.push(m) v, n, l = self.checkMinMax(board, False, depth - 1) if v > value: @@ -110,7 +117,7 @@ class MinmaxPlayerEngine(PlayerEngine): else: value = math.inf - for m in board.legal_moves(): + for m in self.get_player_moves(board): board.push(m) v, n, l = self.checkMinMax(board, True, depth - 1) if v < value: @@ -130,8 +137,7 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes = 1 leafs = 0 move = [] - all_moves = board.legal_moves() - for m in all_moves: + for m in self.get_player_moves(board): board.push(m) value, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta) board.pop() @@ -161,8 +167,7 @@ class AlphabetaPlayerEngine(PlayerEngine): return self.heuristic.get(board, self.player), nodes, leafs if friend_move: - all_moves = board.legal_moves() - for m in all_moves: + for m in self.get_player_moves(board): board.push(m) v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) board.pop() @@ -178,8 +183,7 @@ class AlphabetaPlayerEngine(PlayerEngine): return alpha, nodes, leafs else: - all_moves = board.legal_moves() - for m in all_moves: + for m in self.get_player_moves(board): board.push(m) v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta) board.pop(); @@ -247,7 +251,7 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): def get_move(self, board): - super().get_move(board) + #super().get_move(board) self.interrupt_search = False # Get an alarm signal to stop iterations @@ -282,10 +286,16 @@ class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): alpha )) depth = depth + 1 - self.logger.debug("id_alphabeta - depth reached: {} | max depth : {}".format( + self.logger.info("id_alphabeta - depth reached: {} | max depth : {}".format( depth - 1, max_depth )) + self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( + nodes, + leafs, + alpha + )) + return move def alarm_handler(self, signal, frame): From dd70d575d42d9ac4f80e9b5ddb787102feb55e1f Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 21:37:59 +0100 Subject: [PATCH 11/18] Factorize code to remove dulicate parts --- src/classes/Engines.py | 75 ++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index 534699f..d31c5fc 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -71,13 +71,17 @@ class MinmaxPlayerEngine(PlayerEngine): def get_move(self, board): super().get_move(board) + move, score = self._call(board, self.options['depth']) + return move + + def _call(self, board, depth): value = -math.inf nodes = 1 leafs = 0 move = [] for m in self.get_player_moves(board): board.push(m) - v, n, l = self.checkMinMax(board, False, self.options['depth'] - 1) + v, n, l = self.checkMinMax(board, False, depth - 1) if v > value: value = v move = m @@ -94,7 +98,7 @@ class MinmaxPlayerEngine(PlayerEngine): leafs, value )) - return move + return move, value def checkMinMax(self, board, friend_move:bool, depth :int = 2): nodes = 1 @@ -131,6 +135,10 @@ class AlphabetaPlayerEngine(PlayerEngine): def get_move(self, board): super().get_move(board) + move, heuristic = self._call(board, self.options['depth']) + return move + + def _call(self, board, depth): self.logger.debug("Enter AlphaBeta function") alpha = -math.inf beta = math.inf @@ -139,7 +147,7 @@ class AlphabetaPlayerEngine(PlayerEngine): move = [] for m in self.get_player_moves(board): board.push(m) - value, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta) + value, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) board.pop() nodes += n leafs += l @@ -156,7 +164,7 @@ class AlphabetaPlayerEngine(PlayerEngine): leafs, alpha )) - return move + return move, alpha def checkAlphaBeta(self, board, friend_move : bool, depth, alpha, beta): @@ -209,9 +217,7 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): signal.signal(signal.SIGALRM, self.alarm_handler) signal.alarm(self.options['time_limit']) depth = 1 - value = -math.inf - nodes = 1 - leafs = 0 + heuristic = -math.inf move = None # We can go deeper than blank place in our board, then we must get @@ -222,21 +228,14 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): # Iterate depth while our alarm does not trigger and there is enougth # avaiable move to play while not self.interrupt_search and depth <= max_depth: - for m in board.legal_moves(): - board.push(m) - v, n, l = self.checkMinMax(board, False, depth - 1) - if v > value: - value = v - move = m - self.logger.debug("found a better move: {} (heuristic:{})".format( - move, - value - )) - nodes += n - leafs += l - board.pop() + current_move, current_heuristic = self._call(board, depth) + # return the current move onli if heuristic is better than previous + # iteration + if current_heuristic > heuristic: + move = current_move + depth = depth + 1 - self.logger.debug("id_minmax - depth reached: {} | max depth : {}".format( + self.logger.debug("id_minmax - depth reached: {} | max depth : {}".format( depth - 1, max_depth )) @@ -250,18 +249,15 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): + def get_move(self, board): - #super().get_move(board) self.interrupt_search = False # Get an alarm signal to stop iterations signal.signal(signal.SIGALRM, self.alarm_handler) signal.alarm(self.options['time_limit']) depth = 1 - alpha = -math.inf - beta = math.inf - nodes = 1 - leafs = 0 + heuristic = -math.inf move = None # We can go deeper than blank place in our board, then we must get @@ -272,30 +268,17 @@ class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): # Iterate depth while our alarm does not trigger and there is enougth # avaiable move to play while not self.interrupt_search and depth <= max_depth: - for m in board.legal_moves(): - board.push(m) - v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) - board.pop() - nodes += n - leafs += l - if v >= alpha: - alpha = v - move = m - self.logger.debug("found a better move: {} (heuristic:{})".format( - move, - alpha - )) + current_move, current_heuristic = self._call(board, depth) + # return the current move only if heuristic is better than previous + # iteration can be possible id iteration is stopped by timer + if current_heuristic > heuristic: + move = current_move depth = depth + 1 - self.logger.info("id_alphabeta - depth reached: {} | max depth : {}".format( + + self.logger.debug("id_minmax - depth reached: {} | max depth : {}".format( depth - 1, max_depth )) - self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( - nodes, - leafs, - alpha - )) - return move def alarm_handler(self, signal, frame): From 1a670b59b52d79ce20f82f53fabf8a342303a1dd Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:02:12 +0100 Subject: [PATCH 12/18] Weight is now more accurate --- src/classes/Heuristic.py | 42 +++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/classes/Heuristic.py b/src/classes/Heuristic.py index 2656180..16a4a8f 100644 --- a/src/classes/Heuristic.py +++ b/src/classes/Heuristic.py @@ -55,23 +55,44 @@ class WeightHeuristicEngine(HeuristicEngine): # Elements in the corner if pos_x in [0, size -1] and pos_y in [0,size - 1]: - w[pos_x][pos_y] = self.options['weight'][2] + w[pos_x][pos_y] = self.options['weight'][3] + # corners are a bad place! + elif (pos_x in [0, size - 1] and pos_y in [size - 2, 1]) or \ + (pos_x in [1, size -2] and pos_y in [0, size - 1]): + w[pos_x][pos_y] = self.options['weight'][0] + + # in diagonale of the corner too + elif pos_x in [size - 2, 1] and pos_y in [size - 2, 1]: + w[pos_x][pos_y] = int(self.options['weight'][0] * 1.5) + + elif pos_x in [1,size - 2] and pos_y in range(2, size - 2) or \ + pos_y in [1,size - 2] and pos_x in range(2, size - 2) : + w[pos_x][pos_y] = int(self.options['weight'][0] * 0.75) + + # center border : cool but not so... + elif (pos_x in center_range and pos_y in [0, size-1]) or \ + pos_y in center_range and pos_x in [0, size-1]: + w[pos_x][pos_y] = int(self.options['weight'][2] // 1.25) + # Elements on the border elif pos_x in [0, size -1] or pos_y in [0, size -1]: - w[pos_x][pos_y] = self.options['weight'][1] + w[pos_x][pos_y] = self.options['weight'][2] # Element the center elif pos_x in center_range and pos_y in center_range: - w[pos_x][pos_y] = self.options['weight'][0] + w[pos_x][pos_y] = self.options['weight'][1] + return w def show_weights(self): display = "\n |" + sep = "\n----" for x in range(self.options['size']): display += "{:^3}|".format(x) - display += "\n" + sep += '----' + display += sep + "\n" for x in range(self.options['size']): display += "{:^3}|".format(str(x)) for y in range(self.options['size']): @@ -79,18 +100,7 @@ class WeightHeuristicEngine(HeuristicEngine): display += "\n" return display - @staticmethod - def show_weight_score(weights, size): - display = "\n |" - for x in range(size): - display += "{:^3}|".format(x) - display += "\n" - for x in range(size): - display += "{:^3}|".format(str(x)) - for y in range(size): - display += "{:^3}|".format(weights[x][y]) - display += "\n" - return display + class FullHeuristicEngine(WeightHeuristicEngine): def get(self, board, player): From b4a2fd74844282a13e4594578e50d007e9fe6aba Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:45:04 +0100 Subject: [PATCH 13/18] Shuffle on legal_move() by default --- src/classes/Engines.py | 28 +++++++++++++++++----------- src/game.py | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index d31c5fc..b567786 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -8,7 +8,6 @@ class PlayerEngine: self.heuristic = heuristic self.options = options self.interrupt_search = False - self.randomize_moves = False self.logger.info("Init engine {}, options:{}".format( self.__class__.__name__, self.options @@ -21,10 +20,10 @@ class PlayerEngine: )) def get_player_moves(self, board): - if self.randomize_moves is True: - return random.random(board.legal_moves()) - else: - return board.legal_moves() + moves = board.legal_moves() + if self.options['randomize_moves'] is True: + random.shuffle(moves) + return moves @staticmethod def get_player_name(player): @@ -79,7 +78,8 @@ class MinmaxPlayerEngine(PlayerEngine): nodes = 1 leafs = 0 move = [] - for m in self.get_player_moves(board): + moves = self.get_player_moves(board) + for m in moves: board.push(m) v, n, l = self.checkMinMax(board, False, depth - 1) if v > value: @@ -110,7 +110,8 @@ class MinmaxPlayerEngine(PlayerEngine): if friend_move: value = -math.inf - for m in self.get_player_moves(board): + moves = self.get_player_moves(board) + for m in moves: board.push(m) v, n, l = self.checkMinMax(board, False, depth - 1) if v > value: @@ -121,7 +122,8 @@ class MinmaxPlayerEngine(PlayerEngine): else: value = math.inf - for m in self.get_player_moves(board): + moves = self.get_player_moves(board) + for m in moves: board.push(m) v, n, l = self.checkMinMax(board, True, depth - 1) if v < value: @@ -145,7 +147,8 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes = 1 leafs = 0 move = [] - for m in self.get_player_moves(board): + moves = self.get_player_moves(board) + for m in moves: board.push(m) value, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) board.pop() @@ -175,7 +178,9 @@ class AlphabetaPlayerEngine(PlayerEngine): return self.heuristic.get(board, self.player), nodes, leafs if friend_move: - for m in self.get_player_moves(board): + + moves = self.get_player_moves(board) + for m in moves: board.push(m) v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) board.pop() @@ -191,7 +196,8 @@ class AlphabetaPlayerEngine(PlayerEngine): return alpha, nodes, leafs else: - for m in self.get_player_moves(board): + moves = self.get_player_moves(board) + for m in moves: board.push(m) v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta) board.pop(); diff --git a/src/game.py b/src/game.py index 966f832..8c156ed 100755 --- a/src/game.py +++ b/src/game.py @@ -56,7 +56,22 @@ def parse_aguments(): help='Weight table for weight based heuristic engines', type=int, nargs=3, - default=[2,10,25] + default=[-5, 2, 10,25] + ) + parser.add_argument('-bR', '--black-randomize-moves', + help='Apply a random function on moves list before explore the game tree - black player', + type=bool, + default=True, + ) + + parser.add_argument('-wR', '--white-randomize-moves', + help='Apply a random function on moves list before explore the game tree - white player', + type=bool, + default=True, + ) + parser.add_argument('--show-weights-table', + help='Display weight table used in \'weight\' and \'full\' heuristic calculation', + action='store_true', ) debug_group = parser.add_mutually_exclusive_group() @@ -94,6 +109,16 @@ if __name__ == '__main__': tty_handler.setFormatter(CustomFormatter()) logger.addHandler(tty_handler) + # IT shoud be better implemented but no time to make it clean + if args.show_weights_table: + print("{}".format( + heuristic_engine['weight'](logger,{ + 'weight': args.weight, + 'size': 10 + }).show_weights() + )) + exit(0) + # Activate verbose or debug mode if args.verbose is True: logger.setLevel(log.INFO) @@ -102,7 +127,6 @@ if __name__ == '__main__': if args.debug is True: logger.setLevel(log.DEBUG) logger.debug('DEBUG mode activated') - game = Board(10) logger.debug("Init players engines - black:{} / white:{}".format( args.black_engine, @@ -120,7 +144,8 @@ if __name__ == '__main__': ), { 'depth': args.white_depth_exploration, - 'time_limit': 10 + 'time_limit': 10, + 'randomize_moves': args.white_randomize_moves } ) bplayer = player_engines[args.black_engine]( @@ -134,7 +159,8 @@ if __name__ == '__main__': ), { 'depth': args.black_depth_exploration, - 'time_limit': 10 + 'time_limit': 10, + 'randomize_moves': args.black_randomize_moves } ) while ( not game.is_game_over()): From 928cff64009f89041e55667fa7122cd52c36992e Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:48:16 +0100 Subject: [PATCH 14/18] Adjust dome command line parameters --- src/game.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game.py b/src/game.py index 8c156ed..bf30d3d 100755 --- a/src/game.py +++ b/src/game.py @@ -55,7 +55,7 @@ def parse_aguments(): parser.add_argument('--weight', help='Weight table for weight based heuristic engines', type=int, - nargs=3, + nargs=4, default=[-5, 2, 10,25] ) parser.add_argument('-bR', '--black-randomize-moves', @@ -101,7 +101,7 @@ if __name__ == '__main__': "weight": WeightHeuristicEngine, "full": FullHeuristicEngine, } - print("Stating PyReverso...") + print("Starting PyReverso...") args = parse_aguments() logger = log.getLogger() # Create handler for streaming to tty (stderr / stdout) From ebadd02df71be13282a9ff1c013e7b71f600a988 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:51:02 +0100 Subject: [PATCH 15/18] Adjust dome command line parameters --- src/game.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/game.py b/src/game.py index bf30d3d..fcb72b6 100755 --- a/src/game.py +++ b/src/game.py @@ -52,25 +52,25 @@ def parse_aguments(): default='score', ) + parser.add_argument('-br', '--black-randomize-moves', + help='Apply a random function on moves list before explore the game tree - black player', + type=bool, + default=True, + ) + + parser.add_argument('-wr', '--white-randomize-moves', + help='Apply a random function on moves list before explore the game tree - white player', + type=bool, + default=True, + ) parser.add_argument('--weight', help='Weight table for weight based heuristic engines', type=int, nargs=4, default=[-5, 2, 10,25] ) - parser.add_argument('-bR', '--black-randomize-moves', - help='Apply a random function on moves list before explore the game tree - black player', - type=bool, - default=True, - ) - - parser.add_argument('-wR', '--white-randomize-moves', - help='Apply a random function on moves list before explore the game tree - white player', - type=bool, - default=True, - ) parser.add_argument('--show-weights-table', - help='Display weight table used in \'weight\' and \'full\' heuristic calculation', + help='Display weight table used in \'weight\' and \'full\' heuristic calculation and exit', action='store_true', ) From 1e5f87b5afa2e41e3aa0306fe484cdf9430b775a Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:52:05 +0100 Subject: [PATCH 16/18] Add heuritics informations --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b4ddc92..7df21bd 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,8 @@ affichée avec l'option `-d`. ## Choix d'implémentation J'ai avant tout privilégié la personnalisation des différentes paramètres des -différents moteurs composant le jeu. +différents moteurs composant le jeu. Il,e st ainsi plus aisé de tester le +fonctionnement des différents moteurs. ### Classes PlayerEngine @@ -85,15 +86,19 @@ Quatre moteur "joueurs" sont implémentés : maximale définie; * `AphaBeta` utilise *AlphaBeta* pour déterminer le coup à jouer avec une profondeur maximale définie; - * `IterativeDeepeningMinmax` utilise Minmax avec un temps maximum autorisé + * `MinmaxDeepeningMinmax` utilise Minmax avec un temps maximum autorisé; + * `AlphaBetaDeepening` utilise AlphaBeta avec un temps maximum autorisé -Le choix de ces moteur se fait en ligne de commande avec +Le choix de ces moteur se fait en ligne de commande avec les options évoquées +plus haut. ### Classes HeuristicsEngine Plusieurs classes impémentent plusieurs méthodes pour le calcul de -l'heuristique. Comme nous l'avons vu, les moteurs peuvent être choisis en ligne -de commande et de façon indépendante pour les joueurs blanc et noir. +l'heuristique. Toutes les implémentations se trouvent dans le fichier +`./src/classes/Heuristic.py` Comme nous l'avons vu, les moteurs peuvent être +choisis en ligne de commande et de façon indépendante pour les joueurs blanc et +noir. Trois implementation sond disponibles: @@ -112,9 +117,43 @@ ordre d'importance : 1. Les coins représentent les parties les plus importantes; 2. Ensuite vient les bords; - 3. Et enfin les coins. + 3. Et enfin le centre. + +Cependant certaines parties du plateau de jeu sont à éviter : + + * Les cases autour des coins, car elle laisserai la possibilité au joueur + adverse de placer un de ses pions dans le coin. La case en diagonale du coin + est particulièrement sensible. + * Les lignes juste avant les bords, placer un pion à cet endroit permettrai à + l'adversaire de placer un pion sur le bord. Ce ion sera alors p[lus + difficilement *"capturable"* Les poids affectés sont personnalisable via l'options `--weight`, par défaut -nous avons 2, 10 et 25. +nous avons -5, 2, 10 et 25. +Voici le tableau des poinds par défaut, il peut être affiché avec l'option +`--show-weights-table`: + +```text +./game.py --show-weights-table +Starting PyReverso... + + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +-------------------------------------------- + 0 |25 |-5 |10 | 8 | 8 | 8 | 8 |10 |-5 |25 | + 1 |-5 |-7 |-3 |-3 |-3 |-3 |-3 |-3 |-7 |-5 | + 2 |10 |-3 | 0 | 0 | 0 | 0 | 0 | 0 |-3 |10 | + 3 | 8 |-3 | 0 | 2 | 2 | 2 | 2 | 0 |-3 | 8 | + 4 | 8 |-3 | 0 | 2 | 2 | 2 | 2 | 0 |-3 | 8 | + 5 | 8 |-3 | 0 | 2 | 2 | 2 | 2 | 0 |-3 | 8 | + 6 | 8 |-3 | 0 | 2 | 2 | 2 | 2 | 0 |-3 | 8 | + 7 |10 |-3 | 0 | 0 | 0 | 0 | 0 | 0 |-3 |10 | + 8 |-5 |-7 |-3 |-3 |-3 |-3 |-3 |-3 |-7 |-5 | + 9 |25 |-5 |10 | 8 | 8 | 8 | 8 |10 |-5 |25 | +``` + + +### À savoir: + +Les pois utilisé pour les heuristiques sont important. [reversi]:https://www.coolmathgames.com/blog/how-to-play-reversi-basics-and-best-strategies From 59047be8d561c5041bcf4452b3d9d381352e1847 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:54:10 +0100 Subject: [PATCH 17/18] Fix iterative deepening start depth --- README.md | 7 +++++-- src/classes/Engines.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7df21bd..619a92c 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,12 @@ Voici la liste des options : blancs * `-bd` | `--black-depth-exploration`: niveau d'eploration de l'arbre de jeu pour le joueur au pions noirs, valable pour les moteurs `minmax` et - `alphabeta` + `alphabeta`. Utilisé aussi pour définit la profondeur de départ pour + l'*iterative deepening* * `-wd` | `--white-depth-exploration`: niveau d'eploration de l'arbre de jeu pour le joueur au pions noirs, valable pour les moteurs `minmax` et - `alphabeta` + `alphabeta`Utilisé aussi pour définit la profondeur de départ pour + l'*iterative deepening* * `-bh` | `--black-heuristic-engine`: moteur heuristique utilisé pour l'exploration de l'arbre de jeu du joueur noir (valable pour les moteur de jeu `minmax` et `alphabeta`) @@ -156,4 +158,5 @@ Starting PyReverso... ### À savoir: Les pois utilisé pour les heuristiques sont important. + [reversi]:https://www.coolmathgames.com/blog/how-to-play-reversi-basics-and-best-strategies diff --git a/src/classes/Engines.py b/src/classes/Engines.py index b567786..f03dcf0 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -222,7 +222,7 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine): # Get an alarm signal to stop iterations signal.signal(signal.SIGALRM, self.alarm_handler) signal.alarm(self.options['time_limit']) - depth = 1 + depth = self.options['depth'] heuristic = -math.inf move = None @@ -262,7 +262,7 @@ class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): # Get an alarm signal to stop iterations signal.signal(signal.SIGALRM, self.alarm_handler) signal.alarm(self.options['time_limit']) - depth = 1 + depth = self.options['depth'] heuristic = -math.inf move = None From eb29f45de2382d76ccd38accddb562a306df171b Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Wed, 20 Dec 2023 22:55:07 +0100 Subject: [PATCH 18/18] Revole some debug log --- src/classes/Engines.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/classes/Engines.py b/src/classes/Engines.py index f03dcf0..6be23b4 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -188,10 +188,6 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes += n leafs += l if alpha >= beta: - self.logger.debug("\t - Beta pruning - alpha:{} / beta:{}".format( - alpha, - beta - )) return beta, nodes, leafs return alpha, nodes, leafs @@ -205,10 +201,6 @@ class AlphabetaPlayerEngine(PlayerEngine): nodes += n leafs += l if alpha >= beta: - self.logger.debug("\t - Alpha pruning | alpha:{} | beta:{}".format( - alpha, - beta - )) return alpha, nodes, leafs return beta, nodes, leafs