project_reversi/src/classes/Heuristic.py

164 lines
5.2 KiB
Python

"""
Base class for heuristic object
"""
class HeuristicEngine:
"""
Init method
@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
self.logger.info("Heuristic engine {}, options:{}".format(
self.__class__.__name__,
self.options
))
def get():
raise NotImplementedError
"""
Score based heuristic class
"""
class ScoreHeuristicEngine(HeuristicEngine):
"""
Get score
@param board: reversi board object
@return score: int
"""
def get(self, board, player):
return board.heuristique(player)
"""
Weight based heuristic class
"""
class WeightHeuristicEngine(HeuristicEngine):
"""
Init method
@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']
w = [[ 0 for _ in range(size)] for _ in range(size)]
for pos_x in range(self.options['size']):
for pos_y in range(self.options['size']):
p = board._board[pos_x][pos_y]
if p == player:
score += self.weights[pos_x][pos_y]
w[pos_x][pos_y] = self.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
"""
Get weight array calculated with weight given with options
@param : none
@return 2D array
"""
def _get_weight_array(self):
size = self.options['size']
w = [[ 0 for _ in range(size)] for _ in range(size)]
padding = size // 5
center = size // 2
full_range = range(self.options['size'])
center_range = range(center - padding, center + padding)
for pos_y in full_range:
for pos_x in full_range:
# Elements in the corner
if pos_x in [0, size -1] and pos_y in [0,size - 1]:
w[pos_x][pos_y] = self.options['weight'][3]
# 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
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]
return w
"""
Create a "displayable" array of value dor the calculated weight table
@input none
@return string
"""
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
"""
Full heuristic class
"""
class FullHeuristicEngine(WeightHeuristicEngine):
"""
Get score
@param board: reversi board object
@param player: int concerned player
@return int
"""
def get(self, board, player):
return self.get_weight(board, player) + board.heuristique(player)