Compare commits

..

No commits in common. "eb29f45de2382d76ccd38accddb562a306df171b" and "437f05c8b2bc0db7020347c71396ebaeb767464d" have entirely different histories.

5 changed files with 123 additions and 280 deletions

View file

@ -34,12 +34,10 @@ Voici la liste des options :
blancs blancs
* `-bd` | `--black-depth-exploration`: niveau d'eploration de l'arbre de jeu * `-bd` | `--black-depth-exploration`: niveau d'eploration de l'arbre de jeu
pour le joueur au pions noirs, valable pour les moteurs `minmax` et pour le joueur au pions noirs, valable pour les moteurs `minmax` et
`alphabeta`. Utilisé aussi pour définit la profondeur de départ pour `alphabeta`
l'*iterative deepening*
* `-wd` | `--white-depth-exploration`: niveau d'eploration de l'arbre de jeu * `-wd` | `--white-depth-exploration`: niveau d'eploration de l'arbre de jeu
pour le joueur au pions noirs, valable pour les moteurs `minmax` et pour le joueur au pions noirs, valable pour les moteurs `minmax` et
`alphabeta`Utilisé aussi pour définit la profondeur de départ pour `alphabeta`
l'*iterative deepening*
* `-bh` | `--black-heuristic-engine`: moteur heuristique utilisé pour * `-bh` | `--black-heuristic-engine`: moteur heuristique utilisé pour
l'exploration de l'arbre de jeu du joueur noir (valable pour les moteur de l'exploration de l'arbre de jeu du joueur noir (valable pour les moteur de
jeu `minmax` et `alphabeta`) jeu `minmax` et `alphabeta`)
@ -55,8 +53,7 @@ affichée avec l'option `-d`.
## Choix d'implémentation ## Choix d'implémentation
J'ai avant tout privilégié la personnalisation des différentes paramètres des J'ai avant tout privilégié la personnalisation des différentes paramètres des
différents moteurs composant le jeu. Il,e st ainsi plus aisé de tester le différents moteurs composant le jeu.
fonctionnement des différents moteurs.
### Classes PlayerEngine ### Classes PlayerEngine
@ -88,19 +85,15 @@ Quatre moteur "joueurs" sont implémentés :
maximale définie; maximale définie;
* `AphaBeta` utilise *AlphaBeta* pour déterminer le coup à jouer avec une * `AphaBeta` utilise *AlphaBeta* pour déterminer le coup à jouer avec une
profondeur maximale définie; profondeur maximale définie;
* `MinmaxDeepeningMinmax` utilise Minmax avec un temps maximum autorisé; * `IterativeDeepeningMinmax` 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 les options évoquées Le choix de ces moteur se fait en ligne de commande avec
plus haut.
### Classes HeuristicsEngine ### Classes HeuristicsEngine
Plusieurs classes impémentent plusieurs méthodes pour le calcul de Plusieurs classes impémentent plusieurs méthodes pour le calcul de
l'heuristique. Toutes les implémentations se trouvent dans le fichier l'heuristique. Comme nous l'avons vu, les moteurs peuvent être choisis en ligne
`./src/classes/Heuristic.py` Comme nous l'avons vu, les moteurs peuvent être de commande et de façon indépendante pour les joueurs blanc et noir.
choisis en ligne de commande et de façon indépendante pour les joueurs blanc et
noir.
Trois implementation sond disponibles: Trois implementation sond disponibles:
@ -119,44 +112,9 @@ ordre d'importance :
1. Les coins représentent les parties les plus importantes; 1. Les coins représentent les parties les plus importantes;
2. Ensuite vient les bords; 2. Ensuite vient les bords;
3. Et enfin le centre. 3. Et enfin les coins.
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 Les poids affectés sont personnalisable via l'options `--weight`, par défaut
nous avons -5, 2, 10 et 25. nous avons 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 [reversi]:https://www.coolmathgames.com/blog/how-to-play-reversi-basics-and-best-strategies

View file

@ -8,7 +8,7 @@ class CustomFormatter(logging.Formatter):
red = "\x1b[31;20m" red = "\x1b[31;20m"
bold_red = "\x1b[31;1m" bold_red = "\x1b[31;1m"
reset = "\x1b[0m" reset = "\x1b[0m"
format = "%(levelname)s: %(message)s" format = "%(levelname)s: %(message)s (%(filename)s:%(lineno)d)"
FORMATS = { FORMATS = {
logging.DEBUG: blue + format + reset, logging.DEBUG: blue + format + reset,

View file

@ -1,4 +1,4 @@
import random, math, time, signal import random, math, time
class PlayerEngine: class PlayerEngine:
def __init__(self, player, logger, heuristic, options: dict = {}): def __init__(self, player, logger, heuristic, options: dict = {}):
@ -7,7 +7,6 @@ class PlayerEngine:
self.logger = logger self.logger = logger
self.heuristic = heuristic self.heuristic = heuristic
self.options = options self.options = options
self.interrupt_search = False
self.logger.info("Init engine {}, options:{}".format( self.logger.info("Init engine {}, options:{}".format(
self.__class__.__name__, self.__class__.__name__,
self.options self.options
@ -19,15 +18,9 @@ class PlayerEngine:
self.get_player_name(self.player) self.get_player_name(self.player)
)) ))
def get_player_moves(self, board):
moves = board.legal_moves()
if self.options['randomize_moves'] is True:
random.shuffle(moves)
return moves
@staticmethod @staticmethod
def get_player_name(player): def get_player_name(player):
return 'White (O)' if player == 2 else 'Black (X)' return 'White (O)' if player is 2 else 'Black (X)'
class RandomPlayerEngine(PlayerEngine): class RandomPlayerEngine(PlayerEngine):
def get_move(self, board): def get_move(self, board):
@ -67,25 +60,19 @@ class HumanPlayerEngine(PlayerEngine):
return [board._nextPlayer, x, y] return [board._nextPlayer, x, y]
class MinmaxPlayerEngine(PlayerEngine): class MinmaxPlayerEngine(PlayerEngine):
def get_move(self, board): def get_move(self, board):
super().get_move(board) super().get_move(board)
move, score = self._call(board, self.options['depth'])
return move
def _call(self, board, depth):
value = -math.inf value = -math.inf
nodes = 1 nodes = 1
leafs = 0 leafs = 0
move = [] move = ''
moves = self.get_player_moves(board) for m in board.legal_moves():
for m in moves:
board.push(m) board.push(m)
v, n, l = self.checkMinMax(board, False, depth - 1) v, n, l = self.checkMinMax(board, False, self.options['depth'] - 1)
if v > value: if v > value:
value = v value = v
move = m move = m
self.logger.debug("\tfound a better move: {} (heuristic:{})".format( self.logger.debug("found a better move: {} (heuristic:{})".format(
move, move,
value value
)) ))
@ -93,25 +80,23 @@ class MinmaxPlayerEngine(PlayerEngine):
leafs += l leafs += l
board.pop() board.pop()
self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( self.logger.debug("Tree statistics:\n\tnodes:{}\n\tleafs:{}".format(
nodes, nodes,
leafs, leafs
value ))
)) return move
return move, value
def checkMinMax(self, board, friend_move:bool, depth :int = 2): def checkMinMax(self, board, friend_move:bool, depth :int = 2):
nodes = 1 nodes = 1
leafs = 0 leafs = 0
move = [] move = ''
if depth == 0 or board.is_game_over() or self.interrupt_search: if depth == 0:
leafs +=1 leafs +=1
return self.heuristic.get(board, self.player), nodes, leafs return self.heuristic.get(board, self.player), nodes, leafs
if friend_move: if friend_move:
value = -math.inf value = -math.inf
moves = self.get_player_moves(board) for m in board.legal_moves():
for m in moves:
board.push(m) board.push(m)
v, n, l = self.checkMinMax(board, False, depth - 1) v, n, l = self.checkMinMax(board, False, depth - 1)
if v > value: if v > value:
@ -122,8 +107,7 @@ class MinmaxPlayerEngine(PlayerEngine):
else: else:
value = math.inf value = math.inf
moves = self.get_player_moves(board) for m in board.legal_moves():
for m in moves:
board.push(m) board.push(m)
v, n, l = self.checkMinMax(board, True, depth - 1) v, n, l = self.checkMinMax(board, True, depth - 1)
if v < value: if v < value:
@ -137,148 +121,126 @@ class AlphabetaPlayerEngine(PlayerEngine):
def get_move(self, board): def get_move(self, board):
super().get_move(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 alpha = -math.inf
beta = math.inf beta = math.inf
nodes = 1 nodes = 1
leafs = 0 leafs = 0
move = [] move = []
moves = self.get_player_moves(board) value = -math.inf
for m in moves: for m in board.legal_moves():
board.push(m) board.push(m)
value, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) v, n, l = self.checkAlphaBeta(board, False, self.options['depth'] - 1, alpha, beta)
board.pop() board.pop()
alpha = max(alpha,v)
nodes += n nodes += n
leafs += l leafs += l
if value >= alpha: if alpha >= value:
alpha = value value = alpha
move = m move = m
self.logger.debug("\t-> found a better move: {} | heuristic:{})".format( self.logger.debug("found a better move: {} (heuristic:{})".format(
move, move,
alpha alpha
)) ))
self.logger.info("Tree statistics:\n\tnodes:{}\n\tleafs:{}\n\theuristic:{}".format( self.logger.debug("Tree statistics:\n\tnodes:{}\n\tleafs:{}".format(
nodes, nodes,
leafs, leafs
alpha
)) ))
return move, alpha return move
def checkAlphaBeta(self, board, friend_move : bool, depth, alpha, beta): def checkAlphaBeta(self, board, friend_move : bool, depth, alpha, beta):
nodes = 1 nodes = 1
leafs = 0 leafs = 0
if depth == 0 or board.is_game_over() or self.interrupt_search: if depth == 0 :
leafs +=1 leafs +=1
return self.heuristic.get(board, self.player), nodes, leafs return self.heuristic.get(board, self.player), nodes, leafs
if friend_move: if friend_move:
value = -math.inf
moves = self.get_player_moves(board) for m in board.legal_moves():
for m in moves:
board.push(m) board.push(m)
v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta) v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta)
board.pop() board.pop()
alpha = max(alpha,v) alpha = max(value,v)
nodes += n nodes += n
leafs += l leafs += l
if alpha >= beta: if alpha >= beta:
self.logger.debug("Alpha pruning - alpha:{} / beta:{}".format(
alpha,
beta
))
return beta, nodes, leafs return beta, nodes, leafs
return alpha, nodes, leafs return alpha, nodes, leafs
else: else:
moves = self.get_player_moves(board) value = math.inf
for m in moves: for m in board.legal_moves():
board.push(m) board.push(m)
v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta) v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta)
board.pop(); board.pop();
beta = min(beta, v) beta = min(beta,v)
nodes += n nodes += n
leafs += l leafs += l
if alpha >= beta: if alpha >= beta:
self.logger.debug("Beta pruning - alpha:{} / beta:{}".format(
alpha,
beta
))
return alpha, nodes, leafs return alpha, nodes, leafs
return beta, nodes, leafs return beta, nodes, leafs
class MinmaxDeepeningPlayerEngine(PlayerEngine):
class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine):
def get_move(self, board): def get_move(self, board):
super().get_move(board) super().get_move(board)
self.interrupt_search = False value = -math.inf
nodes = 1
# Get an alarm signal to stop iterations leafs = 0
signal.signal(signal.SIGALRM, self.alarm_handler) move = ''
signal.alarm(self.options['time_limit']) start_time = time.time()
depth = self.options['depth'] for m in board.legal_moves():
heuristic = -math.inf board.push(m)
move = None v, n, l = self.checkMinMax(board, False, start_time)
if v > value:
# We can go deeper than blank place in our board, then we must get value = v
# numbers of avaible place move = m
max_depth = (board.get_board_size()**2) - ( self.logger.debug("found a better move: {} (heuristic:{})".format(
board.get_nb_pieces()[0] + board.get_nb_pieces()[1]) move,
value
# Iterate depth while our alarm does not trigger and there is enougth ))
# avaiable move to play nodes += n
while not self.interrupt_search and depth <= max_depth: leafs += l
current_move, current_heuristic = self._call(board, depth) board.pop()
# 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(
depth - 1,
max_depth
))
return move return move
def alarm_handler(self, signal, frame): def checkMinMax(self, board, friend_move:bool, start_time):
self.logger.debug("Raise SIGALMR Signal") nodes = 1
self.interrupt_search = True 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:
class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine): value = math.inf
for m in board.legal_moves():
board.push(m)
def get_move(self, board): v, n, l = self.checkMinMax(board, True, start_time)
self.interrupt_search = False if v < value:
value = v
# Get an alarm signal to stop iterations board.pop();
signal.signal(signal.SIGALRM, self.alarm_handler) nodes += n
signal.alarm(self.options['time_limit']) leafs += l
depth = self.options['depth'] return value, nodes, leafs
heuristic = -math.inf
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:
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.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

View file

@ -17,90 +17,42 @@ class ScoreHeuristicEngine(HeuristicEngine):
class WeightHeuristicEngine(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): def get(self, board, player):
score = self.get_weight(board, player) score = self.get_weight(board, player)
return score return score
def get_weight(self, board, player): def get_weight(self, board, player):
score = 0 score = 0
size = self.options['size'] size = board.get_board_size()
w = [[ 0 for _ in range(size)] for _ in range(size)] weights = self._get_weight_array(size)
for pos_x in range(self.options['size']): for pos_x in range(size):
for pos_y in range(self.options['size']): for pos_y in range(size):
p = board._board[pos_x][pos_y] if board._board[pos_x][pos_y] == player:
if p == player: score += weights[pos_x][pos_y]
score += self.weights[pos_x][pos_y] else:
w[pos_x][pos_y] = self.weights[pos_x][pos_y] score -= 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 return score
def _get_weight_array(self): def _get_weight_array(self, size):
size = self.options['size']
w = [[ 0 for _ in range(size)] for _ in range(size)] w = [[ 0 for _ in range(size)] for _ in range(size)]
padding = size // 5 padding = size // 5
center = size // 2 center = size // 2
full_range = range(self.options['size']) for pos_y in range(size):
center_range = range(center - padding, center + padding) for pos_x in range(size):
for pos_y in full_range:
for pos_x in full_range:
# Elements in the corner # Elements in the corner
if pos_x in [0, size -1] and pos_y in [0,size - 1]: if pos_x in [0, size -1] and pos_y in [0,size - 1]:
w[pos_x][pos_y] = self.options['weight'][3] w[pos_x][pos_y] = self.options['weight'][2]
# 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 # Elements on the border
elif pos_x in [0, size -1] or pos_y in [0, size -1]: elif pos_x in [0, size -1] or pos_y in [0, size -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'][1] 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):
w[pos_x][pos_y] = self.options['weight'][0]
return w return w
def show_weights(self):
display = "\n |"
sep = "\n----"
for x in range(self.options['size']):
display += "{:^3}|".format(x)
sep += '----'
display += sep + "\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
class FullHeuristicEngine(WeightHeuristicEngine): class FullHeuristicEngine(WeightHeuristicEngine):
def get(self, board, player): def get(self, board, player):

View file

@ -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, MinmaxDeepeningPlayerEngine, AlphaBetaDeepeningPlayerEngine 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', 'id_minmax', 'id_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')
@ -52,26 +52,11 @@ def parse_aguments():
default='score', 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', parser.add_argument('--weight',
help='Weight table for weight based heuristic engines', help='Weight table for weight based heuristic engines',
type=int, type=int,
nargs=4, nargs=3,
default=[-5, 2, 10,25] default=[2,10,25]
)
parser.add_argument('--show-weights-table',
help='Display weight table used in \'weight\' and \'full\' heuristic calculation and exit',
action='store_true',
) )
debug_group = parser.add_mutually_exclusive_group() debug_group = parser.add_mutually_exclusive_group()
@ -94,14 +79,13 @@ if __name__ == '__main__':
"minmax": MinmaxPlayerEngine, "minmax": MinmaxPlayerEngine,
"alphabeta": AlphabetaPlayerEngine, "alphabeta": AlphabetaPlayerEngine,
"id_minmax": MinmaxDeepeningPlayerEngine, "id_minmax": MinmaxDeepeningPlayerEngine,
"id_alphabeta": AlphaBetaDeepeningPlayerEngine
} }
heuristic_engine = { heuristic_engine = {
"score": ScoreHeuristicEngine, "score": ScoreHeuristicEngine,
"weight": WeightHeuristicEngine, "weight": WeightHeuristicEngine,
"full": FullHeuristicEngine, "full": FullHeuristicEngine,
} }
print("Starting PyReverso...") print("Stating PyReverso...")
args = parse_aguments() args = parse_aguments()
logger = log.getLogger() logger = log.getLogger()
# Create handler for streaming to tty (stderr / stdout) # Create handler for streaming to tty (stderr / stdout)
@ -109,16 +93,6 @@ if __name__ == '__main__':
tty_handler.setFormatter(CustomFormatter()) tty_handler.setFormatter(CustomFormatter())
logger.addHandler(tty_handler) 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 # Activate verbose or debug mode
if args.verbose is True: if args.verbose is True:
logger.setLevel(log.INFO) logger.setLevel(log.INFO)
@ -127,6 +101,7 @@ if __name__ == '__main__':
if args.debug is True: if args.debug is True:
logger.setLevel(log.DEBUG) logger.setLevel(log.DEBUG)
logger.debug('DEBUG mode activated') logger.debug('DEBUG mode activated')
game = Board(10) game = Board(10)
logger.debug("Init players engines - black:{} / white:{}".format( logger.debug("Init players engines - black:{} / white:{}".format(
args.black_engine, args.black_engine,
@ -138,14 +113,12 @@ if __name__ == '__main__':
logger, logger,
heuristic_engine[args.white_heuristic_engine]( heuristic_engine[args.white_heuristic_engine](
logger, { logger, {
'weight': args.weight, 'weight': args.weight
'size': game.get_board_size()
} }
), ),
{ {
'depth': args.white_depth_exploration, 'depth': args.white_depth_exploration,
'time_limit': 10, 'time_limit': 10
'randomize_moves': args.white_randomize_moves
} }
) )
bplayer = player_engines[args.black_engine]( bplayer = player_engines[args.black_engine](
@ -153,14 +126,12 @@ if __name__ == '__main__':
logger, logger,
heuristic_engine[args.black_heuristic_engine]( heuristic_engine[args.black_heuristic_engine](
logger, { logger, {
'weight': args.weight, 'weight': args.weight
'size': game.get_board_size()
} }
), ),
{ {
'depth': args.black_depth_exploration, 'depth': args.black_depth_exploration,
'time_limit': 10, 'time_limit': 10
'randomize_moves': args.black_randomize_moves
} }
) )
while ( not game.is_game_over()): while ( not game.is_game_over()):