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,