Skip to content

Commit

Permalink
Update heuristics weights for black and white
Browse files Browse the repository at this point in the history
pieces
  • Loading branch information
MatteoFasulo committed Dec 1, 2023
1 parent 66b6d65 commit 7b8564f
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 66 deletions.
15 changes: 10 additions & 5 deletions blackheuristics.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def black_fitness(board):
fitness = 0

# TODO: Use the correct weights
alpha0 = 0.3
beta0 = 0.5
gamma0 = 0.5820416163057722
theta0 = 1.6675946813493288
alpha0 = 6.0
beta0 = 10.0
gamma0 = 15
theta0 = 900

king_pos = board.get_king()

Expand All @@ -26,14 +26,19 @@ def black_fitness(board):
fitness -= beta0 * len(board.whites)

# Number of black pawns next to the king
fitness += gamma0 * pawns_around(board, king_pos, distance=2)
fitness += gamma0 * pawns_around(board, king_pos, distance=1)

# Free path to the king
free_paths = [board._is_there_a_clear_view(black_pawn, king_pos)
for black_pawn in board.blacks]
# theta0 times the n° free ways to king
fitness += theta0 * sum(free_paths)

# norm_fitness = (fitness / (alpha0 * len(board.blacks) + gamma0 *
# pawns_around(board, king_pos, distance=2) + theta0 * sum(free_paths)))

# print("BLACK FITNESS: ", norm_fitness)

return fitness


Expand Down
28 changes: 12 additions & 16 deletions play.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ def h_alphabeta_search(state, game, cutoff, time_limit=55):
@cache
def max_value(state, alpha, beta, depth, action_backtrack=None):
nonlocal backtrack_dict
if game.terminal_test(state):
if game.terminal_test(state, player):
return game.utility(state, player), None
if cutoff(game, state, depth):
v = game.compute_utility(
state, None, player)
return v, None
return game.compute_utility(
state, player), None
if time.time() - start_time > time_limit:
best_action = max(backtrack_dict, key=backtrack_dict.get)
print("TIMEOUT: ", best_action)
raise TimeoutError(best_action)
v, move = -np.inf, None
if isinstance(state, Tablut):
Expand All @@ -90,25 +90,21 @@ def max_value(state, alpha, beta, depth, action_backtrack=None):
if depth == 0:
from_pos, to_pos = a
if from_pos == state.get_king() and to_pos in state.winning_positions:
print("WINNING POSITION 1")
raise WinException(a)
if from_pos in state.blacks:
king_pos = state.get_king()
coef, blocked_pos = king_surrounded(state)

print(coef, blocked_pos)

if king_pos == (4, 4) and coef == 3 and to_pos in [(3, 4), (5, 4), (4, 3), (4, 5)]:
print("WINNING POSITION 2")
raise WinException(a)

elif king_pos != (4, 4) and coef > 0:
new_state = game.result(state, a)
_, new_blocked_pos = king_surrounded(new_state)

print(new_blocked_pos, "NEW")

# Check if there are two pawns in new_blocked_pos which have same row or same column
if any(p1[0] == p2[0] or p1[1] == p2[1] and p1 != p2 for p1 in new_blocked_pos for p2 in new_blocked_pos):
raise WinException(a)
print("WINNING POSITION 3")
raise WinException(a)

action_backtrack = a
backtrack_dict[a] = 0
Expand All @@ -125,14 +121,14 @@ def max_value(state, alpha, beta, depth, action_backtrack=None):
@cache
def min_value(state, alpha, beta, depth, action_backtrack):
nonlocal backtrack_dict
if game.terminal_test(state):
if game.terminal_test(state, player):
return game.utility(state, player), None
if cutoff(game, state, depth):
v = game.compute_utility(
state, None, player)
return v, None
return game.compute_utility(
state, player), None
if time.time() - start_time > time_limit:
best_action = max(backtrack_dict, key=backtrack_dict.get)
print("TIMEOUT: ", best_action)
raise TimeoutError(best_action)
v, move = +np.inf, None
if isinstance(state, Tablut):
Expand Down
69 changes: 28 additions & 41 deletions tablut.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def update_state(self, pieces, turn):
king_pos = self.initial.get_king()

# Shuffle the list of possible moves
random.shuffle(white_pos)
# random.shuffle(white_pos)
# random.shuffle(black_pos)

# White has also the king
white_pos.insert(0, king_pos)
Expand Down Expand Up @@ -298,15 +299,13 @@ def result(self, state, move, flag: bool = False):

game.update_state(game.initial.pieces, game.initial.to_move)

win = self.terminal_test(game.initial)

# Compute the utility of the board
fitness = self.compute_utility(
game.initial, move, player=game.initial.to_move)

# Update the utility of the board
game.initial.utility = (
0 if not win else fitness if game.initial.to_move == 'WHITE' else -fitness)
game.initial.utility = self.compute_utility(
game.initial, player=game.initial.to_move)

print("UTILITY: ", game.initial.utility)

# return the new board
return game.initial
Expand All @@ -321,9 +320,9 @@ def utility(self, board, player):
Returns:
int: The utility value for the specified player.
"""
return board.utility if player == 'WHITE' else -board.utility
return board.utility if player == 'WHITE' else board.utility

def terminal_test(self, board):
def terminal_test(self, board, player):
"""
Check if the current board state is a terminal state.
Expand All @@ -333,34 +332,22 @@ def terminal_test(self, board):
Returns:
- True if the game is in a terminal state (winning move or no more moves), False otherwise.
"""
return self.check_win(board)

def compute_utility(self, board, move, player) -> float:
"""
alpha : is_white_gonna_be_eaten
beta : external_pawn_more_fitness
gamma : white_pieces
theta : black_pieces
epsilon : king_movement
"""
return self.check_win(board, player)

if player == 'WHITE':
# print(move, board.get_king())
if move and move[0] == board.get_king() and move[1] in board.winning_positions:
return 1e10
def compute_utility(self, board, player) -> float:

# Additional heuristics
fitness = white_fitness(board)
# print(f"Fitness: {fitness}")

elif player == 'BLACK':
if self.check_win(board, player):
return +1e10 if player == 'WHITE' else -1e10
else:
if player == 'WHITE':
fitness = white_fitness(board)

fitness = black_fitness(board)
# print(f"Fitness: {fitness}")
elif player == 'BLACK':
fitness = black_fitness(board)

return fitness
return fitness

def check_win(self, state):
def check_win(self, state, player):
"""
End of game:
- King captured (BLACK wins)
Expand All @@ -379,17 +366,17 @@ def check_win(self, state):
black_pieces = state.initial.get_black()
king_pieces = state.initial.get_king()

# No more white pawns
if len(white_pieces) == 0:
return True
if player == 'WHITE':
if len(black_pieces) == 0:
return True

# No more black pawns
if len(black_pieces) == 0:
return True
elif player == 'BLACK':
# King captured
if king_pieces is None:
return True

# King is dead (captured)
if king_pieces is None:
return True # king is dead
if len(white_pieces) == 0:
return True

return False

Expand Down
30 changes: 26 additions & 4 deletions whiteheuristics.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import math
from utils import RED, RED2, BLUE, Pawn
import copy

Expand Down Expand Up @@ -85,21 +86,42 @@ def white_fitness(board):
theta0 = 0
epsilon0 = 0

king_pos = board.get_king()

alpha0, beta0, gamma0, theta0, epsilon0 = [
0.41639120828483156, 0.723587137336777, 9, 1.06923818569000507, 2.115749207248323]
0.21639120828483156, 0.723587137336777, 9, 1.06923818569000507, 2.115749207248323]

alpha0, beta0, gamma0, theta0, epsilon0, omega0 = [
12, 22, 9, 1, 2, 20]

fitness = 0
# Whitepieces
fitness -= alpha0 * len(board.blacks)

# Blackpieces
fitness += beta0 * len(board.whites)
num_blacks = len(board.blacks)
fitness -= alpha0 * num_blacks

# whitepieces
num_whites = len(board.whites)
fitness += beta0 * num_whites

# king distance
fitness += king_distance_from_center(board.king) * gamma0

# free ways
free_paths = [board._is_there_a_clear_view(black_pawn, king_pos)
for black_pawn in board.blacks]
# theta0 times the n° free ways to king
fitness -= omega0 * sum(free_paths)

# king surrounded
king_vals, _ = king_surrounded(board)
fitness -= king_vals * theta0

fitness += position_weight(board.king) * epsilon0

norm_fitness = (
fitness / (16 * beta0 + math.sqrt(32) * gamma0 + 20*epsilon0))

# print("WHITE FITNESS: ", norm_fitness)

return fitness

0 comments on commit 7b8564f

Please sign in to comment.