First implementation of Iterative Deepening MinMax
This commit is contained in:
parent
e506bcdab9
commit
437f05c8b2
3 changed files with 77 additions and 4 deletions
17
README.md
17
README.md
|
@ -70,9 +70,24 @@ class MinmaxPlayerEngine(PlayerEngine):
|
||||||
|
|
||||||
class RandomPlayerEngine(PlayerEngine):
|
class RandomPlayerEngine(PlayerEngine):
|
||||||
def get_move(board):
|
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 `<pos_x><pos_y>`. 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
|
### Classes HeuristicsEngine
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import random, math
|
import random, math, time
|
||||||
|
|
||||||
class PlayerEngine:
|
class PlayerEngine:
|
||||||
def __init__(self, player, logger, heuristic, options: dict = {}):
|
def __init__(self, player, logger, heuristic, options: dict = {}):
|
||||||
|
@ -189,3 +189,58 @@ class AlphabetaPlayerEngine(PlayerEngine):
|
||||||
))
|
))
|
||||||
return alpha, nodes, leafs
|
return alpha, nodes, leafs
|
||||||
return beta, 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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from classes.Reversi import Board
|
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
|
from classes.Heuristic import ScoreHeuristicEngine, WeightHeuristicEngine, FullHeuristicEngine
|
||||||
import logging as log
|
import logging as log
|
||||||
import argparse as arg
|
import argparse as arg
|
||||||
|
@ -12,7 +12,7 @@ from classes.CustomFormater import CustomFormatter
|
||||||
Function to parse command line arguments
|
Function to parse command line arguments
|
||||||
"""
|
"""
|
||||||
def parse_aguments():
|
def parse_aguments():
|
||||||
engines_choices=['random', 'human', 'minmax', 'alphabeta']
|
engines_choices=['random', 'human', 'minmax', 'alphabeta', 'id_minmax']
|
||||||
heuristic_choices=['score', 'weight', 'full']
|
heuristic_choices=['score', 'weight', 'full']
|
||||||
parser = arg.ArgumentParser('Playing Reversi with (virtual) friend')
|
parser = arg.ArgumentParser('Playing Reversi with (virtual) friend')
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ if __name__ == '__main__':
|
||||||
"human": HumanPlayerEngine,
|
"human": HumanPlayerEngine,
|
||||||
"minmax": MinmaxPlayerEngine,
|
"minmax": MinmaxPlayerEngine,
|
||||||
"alphabeta": AlphabetaPlayerEngine,
|
"alphabeta": AlphabetaPlayerEngine,
|
||||||
|
"id_minmax": MinmaxDeepeningPlayerEngine,
|
||||||
}
|
}
|
||||||
heuristic_engine = {
|
heuristic_engine = {
|
||||||
"score": ScoreHeuristicEngine,
|
"score": ScoreHeuristicEngine,
|
||||||
|
@ -117,6 +118,7 @@ if __name__ == '__main__':
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
'depth': args.white_depth_exploration,
|
'depth': args.white_depth_exploration,
|
||||||
|
'time_limit': 10
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
bplayer = player_engines[args.black_engine](
|
bplayer = player_engines[args.black_engine](
|
||||||
|
@ -129,6 +131,7 @@ if __name__ == '__main__':
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
'depth': args.black_depth_exploration,
|
'depth': args.black_depth_exploration,
|
||||||
|
'time_limit': 10
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
while ( not game.is_game_over()):
|
while ( not game.is_game_over()):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue