Compare commits

...

3 commits

4 changed files with 109 additions and 15 deletions

View file

@ -19,12 +19,34 @@ au programme via la commande `./game.py -h`. Voici quelques exemple de
lancement: lancement:
```shell ```shell
# Lancement de base: les deux joueurs jouent avec le moteur aléatoire: # Lancement de base: les deux joueurs jouent avec le moteur aléatoire et les
options de base:
./game.py ./game.py
# joueur noir humain et joueur blanc MinMax avec une profondeur de 5 # joueur noir humain et joueur blanc MinMax avec une profondeur de 5
./game.py -b human -w minmax --depth 5 ./game.py -be human -we minmax --white-depth-exploration 5
``` ```
Voici la liste des options :
* `-be` | `--black-player-engine`: moteur utilisé par le joueur avec les pions
noirs
* `-we` | `--white-player-engine`: moteur utilisé par le joueur avec les pions
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`
* `-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`
* `-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`)
* `-wh` | `--black-heuristic-engine`: moteur heuristique utilisé pour
l'exploration de l'arbre de jeu du joueur blanc (valable pour les moteur de
jeu `minmax` et `alphabeta`)
L'affichage verbeux est activé avec `-V` et les informations de débogage sont
affichée avec l'option `-d`.
## Choix d'implémentation ## Choix d'implémentation

View file

@ -1,11 +1,15 @@
import random, math import random, math
from .Heuristic import ReversiHeuristic
class PlayerEngine: class PlayerEngine:
def __init__(self, logger, options: dict = {}): def __init__(self, logger, options: dict = {}):
# init logger do display informations # init logger do display informations
self.logger = logger self.logger = logger
self.options = options self.options = options
self.logger.info("Init engine {}".format(self.__class__.__name__)) self.logger.info("Init engine {}, options:{}".format(
self.__class__.__name__,
self.options
))
def get_move(self, board): def get_move(self, board):
self.logger.info("engine: {} - player:{}".format( self.logger.info("engine: {} - player:{}".format(
@ -88,7 +92,11 @@ class MinmaxPlayerEngine(PlayerEngine):
move = '' move = ''
if depth == 0: if depth == 0:
leafs +=1 leafs +=1
return board.heuristique(), nodes, leafs if self.options['heuristic'] == 'weight':
score = ReversiHeuristic(board).get()
else:
score = board.heuristique()
return score, nodes, leafs
if friend_move: if friend_move:
value = -math.inf value = -math.inf
@ -150,7 +158,11 @@ class AlphabetaPlayerEngine(PlayerEngine):
leafs = 0 leafs = 0
if depth == 0 : if depth == 0 :
leafs +=1 leafs +=1
return board.heuristique(), nodes, leafs if self.options['heuristic'] == 'weight':
score = ReversiHeuristic(self.logger).get(board)
else:
score = board.heuristique()
return score, nodes, leafs
if friend_move: if friend_move:
value = -math.inf value = -math.inf

38
src/classes/Heuristic.py Normal file
View file

@ -0,0 +1,38 @@
class ReversiHeuristic():
def __init__(self, logger, weight = [1, 2, 10, 20]):
self.logger = logger
self.weight = weight
def get(self, board):
size = board.get_board_size()
score = 0
weights = self._get_weight(size)
for pos_x in range(size):
for pos_y in range(size):
if board._board[pos_x][pos_y] == board._nextPlayer:
score += weights[pos_x][pos_y]
else:
score -= weights[pos_x][pos_y]
return score
def _get_weight(self, size):
w = [[ 0 for _ in range(size)] for _ in range(size)]
for pos_y in range(size):
for pos_x in range(size):
# Elements in the corner
if pos_x in [0, size -1] and pos_y in [0,size - 1]:
w[pos_x][pos_y] = self.weight[3]
# Elements on the border
elif pos_x in [0, size -1] or pos_y in [0, size -1]:
w[pos_x][pos_y] = self.weight[2]
# Element the center
elif pos_x in range( int(size // 2 - 2), size // 2 + 2) and pos_y in range( size // 2 - 2, size // 2 + 2):
w[pos_x][pos_y] = self.weight[1]
else:
w[pos_x][pos_y] = self.weight[0]
return w

View file

@ -1,4 +1,5 @@
#!/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
import logging as log import logging as log
@ -11,26 +12,45 @@ Function to parse command line arguments
""" """
def parse_aguments(): def parse_aguments():
engines_choices=['random', 'human', 'minmax', 'alphabeta'] engines_choices=['random', 'human', 'minmax', 'alphabeta']
heuristic_choices=['weight',]
parser = arg.ArgumentParser('Playing Reversi with (virtual) friend') parser = arg.ArgumentParser('Playing Reversi with (virtual) friend')
parser.add_argument('-w', '--white-engine', parser.add_argument('-we', '--white-engine',
choices=engines_choices, choices=engines_choices,
help='white player engine (random)', help='white player engine (random)',
default='random' default='random'
) )
parser.add_argument('-b', '--black-engine', parser.add_argument('-be', '--black-engine',
choices=engines_choices, choices=engines_choices,
help='black player engine (random)', help='black player engine (random)',
default='random' default='random'
) )
parser.add_argument('-D', '--depth', parser.add_argument('-bd', '--black-depth-exploration',
help='Minmax exploration depth', help='Black player exploration depth (minmax or alphabeta engine)',
type=int, type=int,
default=3, default=3,
) )
parser.add_argument('-wd', '--white-depth-exploration',
help='White player exploration depth (minmax or alphabeta engine)',
type=int,
default=3,
)
parser.add_argument('-bh', '--black-heuristic-engine',
help='Black player heutistic engine',
choices=['board', 'weight'],
default='board',
)
parser.add_argument('-wh', '--white-heuristic-engine',
help='White player heutistic engine',
choices=['board', 'weight'],
default='board',
)
debug_group = parser.add_mutually_exclusive_group() debug_group = parser.add_mutually_exclusive_group()
debug_group.add_argument('-V', '--verbose', debug_group.add_argument('-V', '--verbose',
help='Verbose output', help='Verbose output',
@ -54,7 +74,6 @@ if __name__ == '__main__':
print("Stating PyReverso...") print("Stating PyReverso...")
args = parse_aguments() args = parse_aguments()
logger = log.getLogger() logger = log.getLogger()
print(args)
# Create handler for streaming to tty (stderr / stdout) # Create handler for streaming to tty (stderr / stdout)
tty_handler = log.StreamHandler() tty_handler = log.StreamHandler()
tty_handler.setFormatter(CustomFormatter()) tty_handler.setFormatter(CustomFormatter())
@ -74,11 +93,14 @@ if __name__ == '__main__':
args.black_engine, args.black_engine,
args.white_engine args.white_engine
)) ))
options = { wplayer = engines[args.white_engine](logger, {
'depth': args.depth 'depth': args.white_depth_exploration,
} 'heuristic': args.white_heuristic_engine
wplayer = engines[args.white_engine](logger, options) })
bplayer = engines[args.black_engine](logger, options) bplayer = engines[args.black_engine](logger, {
'depth': args.black_depth_exploration,
'heuristic': args.black_heuristic_engine
})
while ( not game.is_game_over()): while ( not game.is_game_over()):
if game._nextPlayer == 1: if game._nextPlayer == 1:
move = bplayer.get_move(game) move = bplayer.get_move(game)