164 lines
5.2 KiB
Python
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)
|