diff --git a/README.md b/README.md index 6a86f74..b4ddc92 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,24 @@ class MinmaxPlayerEngine(PlayerEngine): class RandomPlayerEngine(PlayerEngine): def get_move(board): + +# [...] ``` -Il est ainsi plus aisé de tester les moteur dans notre programme de base. +Quatre moteur "joueurs" sont implémentés : + + * `Human` pour gérer des joueurs humain, une saisir utilisateur est demandée + sous la forme ``. Il est aussi possible d'afficher le plateau + avec la commande `print` ou les coups possibles avec `help`; + * `Ramdom` va choisir aléatoirement le coup à jouer en fonction des coups; + possibles; + * `Minmax` utilise *MinMax* pour déterminer le coup à jouer avec une profondeur + 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é + +Le choix de ces moteur se fait en ligne de commande avec ### Classes HeuristicsEngine diff --git a/src/classes/Engines.py b/src/classes/Engines.py index a3d6f54..4ad9d13 100644 --- a/src/classes/Engines.py +++ b/src/classes/Engines.py @@ -1,4 +1,4 @@ -import random, math +import random, math, time class PlayerEngine: def __init__(self, player, logger, heuristic, options: dict = {}): @@ -189,3 +189,58 @@ 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 diff --git a/src/game.py b/src/game.py index 09a079d..6f60705 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 +from classes.Engines import RandomPlayerEngine, HumanPlayerEngine, MinmaxPlayerEngine, AlphabetaPlayerEngine, MinmaxDeepeningPlayerEngine 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'] + engines_choices=['random', 'human', 'minmax', 'alphabeta', 'id_minmax'] heuristic_choices=['score', 'weight', 'full'] parser = arg.ArgumentParser('Playing Reversi with (virtual) friend') @@ -78,6 +78,7 @@ if __name__ == '__main__': "human": HumanPlayerEngine, "minmax": MinmaxPlayerEngine, "alphabeta": AlphabetaPlayerEngine, + "id_minmax": MinmaxDeepeningPlayerEngine, } heuristic_engine = { "score": ScoreHeuristicEngine, @@ -117,6 +118,7 @@ if __name__ == '__main__': ), { 'depth': args.white_depth_exploration, + 'time_limit': 10 } ) bplayer = player_engines[args.black_engine]( @@ -129,6 +131,7 @@ if __name__ == '__main__': ), { 'depth': args.black_depth_exploration, + 'time_limit': 10 } ) while ( not game.is_game_over()):