Make pep8 happy

This commit is contained in:
Yorick Barbanneau 2023-12-22 13:08:26 +01:00
parent 807ae7daa6
commit 6e2d2c2a7b
4 changed files with 181 additions and 131 deletions

View file

@ -1,8 +1,12 @@
import random, math, time, signal
import random
import math
import signal
"""
Base player engine
"""
class PlayerEngine:
"""
@ -12,6 +16,7 @@ class PlayerEngine:
@param heuristic: HeuristicClass object to calculate tree heuristic
@param options: hashtable containing options
"""
def __init__(self, player, logger, heuristic, options: dict = {}):
# init logger do display informations
self.player = player
@ -28,6 +33,7 @@ class PlayerEngine:
get move
@param board: Board
"""
def get_move(self, board):
self.logger.info("engine: {} - player:{}".format(
self._get_class_name(),
@ -39,6 +45,7 @@ class PlayerEngine:
@param none
@return: array
"""
def get_player_moves(self, board):
moves = board.legal_moves()
if self.options['randomize_moves'] is True:
@ -50,6 +57,7 @@ class PlayerEngine:
@param player: int
@return: string
"""
def _get_player_name(self, player):
return 'White (O)' if self.player == 2 else 'Black (X)'
@ -70,17 +78,20 @@ class PlayerEngine:
def _get_class_name(self):
return self.__class__.__name__
"""
Random game engine
"""
class RandomPlayerEngine(PlayerEngine):
class RandomPlayerEngine(PlayerEngine):
"""
Get move return a random move based on Board.legal_moves
@param player: int
@return: array
"""
def get_move(self, board):
super().get_move(board)
moves = board.legal_moves()
@ -90,14 +101,16 @@ class RandomPlayerEngine(PlayerEngine):
"""
Human player engine.
"""
class HumanPlayerEngine(PlayerEngine):
class HumanPlayerEngine(PlayerEngine):
"""
Get move return a move based on user input
@param board: Board
@return: array
"""
def get_move(self, board):
super()
move = None
@ -114,6 +127,7 @@ class HumanPlayerEngine(PlayerEngine):
@param input: string
@return: array
"""
def validate_input(self, input, board):
if input == 'print':
print("\n{}".format(board.show_board()))
@ -141,13 +155,14 @@ class HumanPlayerEngine(PlayerEngine):
self.logger.error("Invalid input must be [A-J][0-9] (was {})".format(input))
return None
return [board._nextPlayer, x, y]
"""
MinMax player engine
"""
class MinmaxPlayerEngine(PlayerEngine):
@ -156,12 +171,12 @@ class MinmaxPlayerEngine(PlayerEngine):
@param board: Board
@return: array
"""
def get_move(self, board):
super().get_move(board)
move, score = self._call(board, self.options['depth'])
return move
"""
First part of the minmax algorithm, it get the best player move based on
max value
@ -169,6 +184,7 @@ class MinmaxPlayerEngine(PlayerEngine):
@param depth: search depth
@return: move and max heuristic
"""
def _call(self, board, depth):
value = -math.inf
nodes = 1
@ -196,10 +212,10 @@ class MinmaxPlayerEngine(PlayerEngine):
@param depth: search depth
@return: heuristic score, nodes ans leafs processed
"""
def checkMinMax(self, board, friend_move: bool, depth: int = 2):
nodes = 1
leafs = 0
move = []
if depth == 0 or board.is_game_over() or self.interrupt_search:
leafs +=1
return self.heuristic.get(board, self.player), nodes, leafs
@ -209,11 +225,11 @@ class MinmaxPlayerEngine(PlayerEngine):
moves = self.get_player_moves(board)
for m in moves:
board.push(m)
v, n, l = self.checkMinMax(board, False, depth - 1)
v, n, le = self.checkMinMax(board, False, depth - 1)
if v > value:
value = v
nodes += n
leafs += l
leafs += le
board.pop()
else:
@ -221,14 +237,15 @@ class MinmaxPlayerEngine(PlayerEngine):
moves = self.get_player_moves(board)
for m in moves:
board.push(m)
v, n, l = self.checkMinMax(board, True, depth - 1)
v, n, le = self.checkMinMax(board, True, depth - 1)
if v < value:
value = v
board.pop();
board.pop()
nodes += n
leafs += l
leafs += le
return value, nodes, leafs
class AlphabetaPlayerEngine(PlayerEngine):
def get_move(self, board):
@ -243,6 +260,7 @@ class AlphabetaPlayerEngine(PlayerEngine):
@param depth: search depth
@return: move and max heuristic
"""
def _call(self, board, depth):
self.logger.debug("Enter AlphaBeta function")
alpha = -math.inf
@ -253,10 +271,10 @@ class AlphabetaPlayerEngine(PlayerEngine):
moves = self.get_player_moves(board)
for m in moves:
board.push(m)
value, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta)
value, n, le = self.checkAlphaBeta(board, False, depth - 1, alpha, beta)
board.pop()
nodes += n
leafs += l
leafs += le
if value >= alpha:
alpha = value
move = m
@ -268,10 +286,12 @@ class AlphabetaPlayerEngine(PlayerEngine):
"""
recursive function to apply alphabeta
@param board: Board
@param friend_move: boolean does function maximise (player turn) or not (opponent turn)
@param friend_move: boolean does function maximise (player turn) or
not (opponent turn)
@param depth: search depth
@return: heuristic score, nodes ans leafs processed
"""
def checkAlphaBeta(self, board, friend_move: bool, depth, alpha, beta):
nodes = 1
leafs = 0
@ -284,11 +304,11 @@ class AlphabetaPlayerEngine(PlayerEngine):
moves = self.get_player_moves(board)
for m in moves:
board.push(m)
v, n, l = self.checkAlphaBeta(board, False, depth - 1, alpha, beta)
v, n, le = self.checkAlphaBeta(board, False, depth - 1, alpha, beta)
board.pop()
alpha = max(alpha, v)
nodes += n
leafs += l
leafs += le
if alpha >= beta:
return beta, nodes, leafs
return alpha, nodes, leafs
@ -297,11 +317,11 @@ class AlphabetaPlayerEngine(PlayerEngine):
moves = self.get_player_moves(board)
for m in moves:
board.push(m)
v, n, l = self.checkAlphaBeta(board, True, depth - 1, alpha, beta)
board.pop();
v, n, le = self.checkAlphaBeta(board, True, depth - 1, alpha, beta)
board.pop()
beta = min(beta, v)
nodes += n
leafs += l
leafs += le
if alpha >= beta:
return alpha, nodes, leafs
return beta, nodes, leafs
@ -313,6 +333,7 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine):
@param board: Board
@return: array
"""
def get_move(self, board):
super().get_move(board)
self.interrupt_search = False
@ -357,7 +378,6 @@ class MinmaxDeepeningPlayerEngine(MinmaxPlayerEngine):
self.interrupt_search = True
class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine):
"""
@ -365,6 +385,7 @@ class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine):
@param board: Board
@return: array
"""
def get_move(self, board):
self.interrupt_search = False
@ -402,6 +423,7 @@ class AlphaBetaDeepeningPlayerEngine(AlphabetaPlayerEngine):
"""
define an handler for the alarm signal
"""
def alarm_handler(self, signal, frame):
self.logger.debug("Raise SIGALMR Signal")
self.interrupt_search = True

View file

@ -1,7 +1,8 @@
"""
Base class for heuristic object
"""
class HeuristicEngine:
"""
@ -9,6 +10,7 @@ class HeuristicEngine:
@param logger: logging object (display verbose and debug messages)
@param options: hashtable contains options like board size or heuristic weight
"""
def __init__(self, logger, options):
self.logger = logger
self.options = options
@ -20,9 +22,12 @@ class HeuristicEngine:
def get():
raise NotImplementedError
"""
Score based heuristic class
"""
class ScoreHeuristicEngine(HeuristicEngine):
"""
@ -30,12 +35,15 @@ class ScoreHeuristicEngine(HeuristicEngine):
@param board: reversi board object
@return score: int
"""
def get(self, board, player):
return board.heuristique(player)
"""
Weight based heuristic class
"""
class WeightHeuristicEngine(HeuristicEngine):
"""
@ -43,29 +51,30 @@ class WeightHeuristicEngine(HeuristicEngine):
@param logger: logging object (display verbose and debug messages)
@param options: hashtable contains options like board size or heuristic weight
"""
def __init__(self, logger, options):
super().__init__(logger, options)
self.weights = self._get_weight_array()
self.logger.debug("{}".format(self.show_weights()))
"""
Get score
@param board: reversi board object
@param player: int concerned player
@return int
"""
def get(self, board, player):
score = self.get_weight(board, player)
return score
"""
Get score based on weight based on a weight-table built on object creation
@param board: reversi board object
@param player: int concerned player
@return int
"""
def get_weight(self, board, player):
score = 0
size = self.options['size']
@ -87,6 +96,7 @@ class WeightHeuristicEngine(HeuristicEngine):
@param : none
@return 2D array
"""
def _get_weight_array(self):
size = self.options['size']
w = [[0 for _ in range(size)] for _ in range(size)]
@ -135,6 +145,7 @@ class WeightHeuristicEngine(HeuristicEngine):
@input none
@return string
"""
def show_weights(self):
display = "\n |"
sep = "\n----"
@ -149,9 +160,12 @@ class WeightHeuristicEngine(HeuristicEngine):
display += "\n"
return display
"""
Full heuristic class
"""
class FullHeuristicEngine(WeightHeuristicEngine):
"""
@ -160,5 +174,6 @@ class FullHeuristicEngine(WeightHeuristicEngine):
@param player: int concerned player
@return int
"""
def get(self, board, player):
return self.get_weight(board, player) + board.heuristique(player)

View file

@ -227,7 +227,7 @@ class Board:
display += " {} |".format(str(x))
for y in range(self.get_board_size()):
display += " {} |".format(self._piece2str(self._board[x][y]))
display += "\n"#+sep+"\n"
display += "\n"
return display + sep + '\n'
def __str__(self):

View file

@ -12,66 +12,78 @@ from classes.CustomFormater import CustomFormatter
"""
Function to parse command line arguments
"""
def parse_aguments():
engines_choices = ['random', 'human', 'minmax', 'alphabeta', 'id_minmax', 'id_alphabeta']
heuristic_choices = ['score', 'weight', 'full']
parser = arg.ArgumentParser('Playing Reversi with (virtual) friend')
parser.add_argument('-we', '--white-engine',
parser.add_argument('-we',
'--white-engine',
choices=engines_choices,
help='white player engine (random)',
default='random'
)
parser.add_argument('-be', '--black-engine',
parser.add_argument('-be',
'--black-engine',
choices=engines_choices,
help='black player engine (random)',
default='random'
)
parser.add_argument('-bd', '--black-depth-exploration',
parser.add_argument('-bd',
'--black-depth-exploration',
help='Black player exploration depth (minmax or alphabeta engine)',
type=int,
default=3,
)
parser.add_argument('-wd', '--white-depth-exploration',
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',
parser.add_argument('-bh',
'--black-heuristic-engine',
help='Black player heutistic engine',
choices= heuristic_choices,
default='score',
)
parser.add_argument('-wh', '--white-heuristic-engine',
parser.add_argument('-wh',
'--white-heuristic-engine',
help='White player heutistic engine',
choices=heuristic_choices,
default='score',
)
parser.add_argument('-br', '--black-randomize-moves',
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',
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('-bt', '--black-player-deepening-time',
parser.add_argument('-bt',
'--black-player-deepening-time',
help='Time interval in seconds for Iterative Deepening - black player',
type=int,
default=10,
)
parser.add_argument('-wt', '--white-player-deepening-time',
parser.add_argument('-wt',
'--white-player-deepening-time',
help='Time interval in seconds for Iterative Deepening - black player',
type=int,
default=10,
@ -84,7 +96,8 @@ def parse_aguments():
default=[-5, 2, 10,25]
)
parser.add_argument('-r', '--recursions',
parser.add_argument('-r',
'--recursions',
help='Number parties to play',
type=int,
default=1