-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Little refactorization and fixed free line evaluation
1 parent
dd6342c
commit cf0ce9e
Showing
12 changed files
with
454 additions
and
358 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,18 @@ | ||
*.python text diff=python | ||
*.python text diff=python | ||
*.py text diff=python | ||
|
||
*.css text diff=css | ||
*.html text diff=html | ||
*.tld text | ||
*.xml text | ||
*.css text diff=css | ||
*.html text diff=html | ||
*.tld text | ||
*.xml text | ||
*.scss text diff=scss | ||
|
||
*.jpg binary | ||
*.jpeg binary | ||
*.png binary | ||
|
||
*.md text diff=markdown | ||
*.mdx text diff=markdown | ||
*.tex text diff=tex | ||
*.pdf diff=astextplain | ||
*.PDF diff=astextplain | ||
*.txt text | ||
|
||
.gitignore export-ignore | ||
.gitattributes export-ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
.idea/ | ||
__pycache__/ | ||
venv/ | ||
src/resources/ui/test.ui | ||
src/resources/ui/test.ui | ||
.fleet/ | ||
.pytest_cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import math | ||
from typing import TYPE_CHECKING | ||
|
||
from numba import jit | ||
from numpy import ndarray | ||
|
||
from game_window.CheckUtil import CheckUtil | ||
from game_window.ColorManager import ColorManager | ||
from game_window.enums.BoardEnum import BoardEnum | ||
|
||
if TYPE_CHECKING: | ||
from game_window.Board import Board | ||
|
||
|
||
class KingPressure: | ||
@staticmethod | ||
def evaluate_king_pressure(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to evaluate pressure on king. | ||
:param board: Board instance | ||
:param favor_color: int value of color in favor of which we evaluate position | ||
:return: int evaluation | ||
""" | ||
enemy_color: int = ColorManager.get_opposite_piece_color(favor_color) | ||
pressure_on_enemy_king = KingPressure.evaluate_king_pressure_only_for_color(board, favor_color) | ||
pressure_on_my_king = KingPressure.evaluate_king_pressure_only_for_color(board, enemy_color) | ||
evaluation: int = int(pressure_on_enemy_king - pressure_on_my_king) | ||
|
||
return evaluation | ||
|
||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_king_pressure_only_for_color(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to evaluate distance of pieces to the enemy king | ||
:param favor_color: int value of color | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
enemy_color: int = ColorManager.get_opposite_piece_color(favor_color) | ||
board_array: ndarray[int] = board.get_board_array() | ||
|
||
enemy_king_pos = CheckUtil.find_friendly_king_squares(board_array, enemy_color) | ||
enemy_king_x = math.floor(enemy_king_pos / 8) | ||
enemy_king_y = enemy_king_pos - 8 * enemy_king_x | ||
score_accumulator = 0 | ||
|
||
for pos in range(BoardEnum.BOARD_SIZE.value): | ||
if ColorManager.get_piece_color(board_array[pos]) != favor_color: | ||
continue | ||
my_piece_x = math.floor(pos / 8) | ||
my_piece_y = pos - 8 * my_piece_x | ||
|
||
x_diff = enemy_king_x - my_piece_x | ||
y_diff = enemy_king_y - my_piece_y | ||
|
||
distance = math.sqrt(x_diff * x_diff + y_diff * y_diff) | ||
score = 8 * math.sqrt(2) - distance | ||
score_accumulator += score | ||
return score_accumulator |
91 changes: 91 additions & 0 deletions
91
src/main/game_window/engine/static_eval/LightPiecesEval.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
from numba import jit | ||
from numpy import array | ||
from numpy import int8 | ||
from numpy import ndarray | ||
|
||
from game_window.ColorManager import ColorManager | ||
from game_window.engine.static_eval.StaticEvalUtil import StaticEvalUtil | ||
from game_window.enums.EvalEnum import EvalEnum | ||
from game_window.enums.PiecesEnum import PiecesEnum | ||
|
||
if TYPE_CHECKING: | ||
from game_window.Board import Board | ||
|
||
|
||
class LightPiecesEval: | ||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_bishops(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to evaluate if player has a pair of bishops. | ||
:param favor_color: int value of color | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
evaluation: int = 0 | ||
board_array: ndarray[int] = board.get_board_array() | ||
engine_color: int = board.get_engine_color() | ||
player_color: int = board.get_player_color() | ||
engine_bishops: int = 0 | ||
player_bishops: int = 0 | ||
|
||
for square, piece in enumerate(board_array): | ||
if piece == PiecesEnum.NONE.value: | ||
continue | ||
|
||
if piece == engine_color | PiecesEnum.BISHOP.value: | ||
engine_bishops += 1 | ||
elif piece == player_color | PiecesEnum.BISHOP.value: | ||
player_bishops += 1 | ||
if engine_bishops >= 2: | ||
evaluation += EvalEnum.BISHOP_PAIR.value | ||
if player_bishops >= 2: | ||
evaluation -= EvalEnum.BISHOP_PAIR.value | ||
return StaticEvalUtil.return_proper_evaluation_signed_value(board, evaluation, favor_color) | ||
|
||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_light_pieces_walked(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to evaluate if light pieces are walked from their starting position | ||
:param favor_color: | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
pieces = array([PiecesEnum.KNIGHT.value, PiecesEnum.BISHOP.value, PiecesEnum.BISHOP.value, PiecesEnum.KNIGHT.value]) | ||
board_array: ndarray[int] = board.get_board_array() | ||
favorable_accumulator: int = 0 | ||
enemy_color: int = ColorManager.get_opposite_piece_color(favor_color) | ||
unfavorable_accumulator: int = 0 | ||
favor_light_walked: int = 0 | ||
un_favor_light_walked: int = 0 | ||
|
||
light_pieces_positions: dict = { | ||
board.get_engine_color(): array([1, 2, 5, 6], dtype=int8), | ||
board.get_player_color(): array([57, 58, 61, 62], dtype=int8), | ||
} | ||
|
||
for i in range(0, 4): | ||
position = light_pieces_positions[favor_color][i] | ||
enemy_position = light_pieces_positions[enemy_color][i] | ||
|
||
if board_array[position] == favor_color | pieces[i]: | ||
favorable_accumulator -= EvalEnum.WALKED.value | ||
else: | ||
favor_light_walked += 1 | ||
favorable_accumulator += EvalEnum.WALKED.value | ||
|
||
if board_array[enemy_position] == enemy_color | pieces[i]: | ||
unfavorable_accumulator -= EvalEnum.WALKED.value | ||
else: | ||
un_favor_light_walked += 1 | ||
unfavorable_accumulator += EvalEnum.WALKED.value | ||
if favor_light_walked != 4 and StaticEvalUtil.is_queen_on_start_position(favor_color, board): | ||
favor_light_walked -= 2 * EvalEnum.WALKED.value | ||
if un_favor_light_walked != 4 and StaticEvalUtil.is_queen_on_start_position(enemy_color, board): | ||
favor_light_walked -= 2 * EvalEnum.WALKED.value | ||
|
||
evaluation: int = favorable_accumulator - unfavorable_accumulator | ||
return StaticEvalUtil.return_proper_evaluation_signed_value(board, evaluation, favor_color) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
from numba import jit | ||
from numpy import ndarray | ||
|
||
from game_window.ColorManager import ColorManager | ||
from game_window.engine.static_eval.StaticEvalUtil import StaticEvalUtil | ||
from game_window.enums.EvalEnum import EvalEnum | ||
from game_window.enums.PiecesEnum import PiecesEnum | ||
|
||
if TYPE_CHECKING: | ||
from game_window.Board import Board | ||
|
||
|
||
class RookEval: | ||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_free_lines_for_rooks(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Methods used to evaluate free lines for rooks | ||
:param favor_color: int value of color | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
board_array: ndarray[int] = board.get_board_array() | ||
evaluation: int = 0 | ||
|
||
for square, piece in enumerate(board_array): | ||
piece_color: int = ColorManager.get_piece_color(piece) | ||
piece_value: int = piece - piece_color | ||
|
||
if piece_value == PiecesEnum.ROOK.value: | ||
free_line_eval = RookEval.get_free_line_eval(board, square) | ||
evaluation += StaticEvalUtil.return_proper_evaluation_signed_value(board, free_line_eval, piece_color) | ||
return StaticEvalUtil.return_proper_evaluation_signed_value(board, evaluation, favor_color) | ||
|
||
@staticmethod | ||
def get_horizontal_eval(start_square: int, board: 'Board') -> int: | ||
""" | ||
Method used to evaluate horizontal lines of rooks | ||
:param start_square: starting square of a rook | ||
:param board: Board instance | ||
:return: int | ||
""" | ||
left_step: int = -1 | ||
right_step: int = 1 | ||
board_array: ndarray[int] = board.get_board_array() | ||
distances: ndarray[int] = board.get_distances() | ||
distance_to_left: int = distances[start_square][3] | ||
distance_to_right: int = distances[start_square][4] | ||
left_border: int = start_square + left_step * distance_to_left - 1 | ||
right_border: int = start_square + right_step * distance_to_right + 1 | ||
|
||
for index in range(start_square - 1, left_border, left_step): | ||
if distance_to_left == 0: | ||
break | ||
|
||
if board_array[index] != PiecesEnum.NONE.value: | ||
return 0 | ||
|
||
for index in range(start_square + 1, right_border, right_step): | ||
if distance_to_right == 0: | ||
break | ||
|
||
if board_array[index] != PiecesEnum.NONE.value: | ||
return 0 | ||
return EvalEnum.FREE_LINE.value | ||
|
||
@staticmethod | ||
def get_vertical_eval(start_square: int, board: 'Board') -> int: | ||
""" | ||
Method used to evaluate vertical lines of rooks | ||
:param start_square: starting square of a rook | ||
:param board: Board instance | ||
:return: int | ||
""" | ||
top_step: int = -8 | ||
bottom_step: int = 8 | ||
board_array: ndarray[int] = board.get_board_array() | ||
distances: ndarray[int] = board.get_distances() | ||
distance_to_top: int = distances[start_square][1] | ||
distance_to_bottom: int = distances[start_square][6] | ||
top_border: int = start_square + top_step * distance_to_top - 1 | ||
bottom_border: int = start_square + bottom_step * distance_to_bottom + 1 | ||
|
||
for index in range(start_square - 8, top_border, top_step): | ||
if distance_to_top == 0: | ||
break | ||
|
||
if board_array[index] != PiecesEnum.NONE.value: | ||
return 0 | ||
|
||
for index in range(start_square + 8, bottom_border, bottom_step): | ||
if distance_to_bottom == 0: | ||
break | ||
|
||
if board_array[index] != PiecesEnum.NONE.value: | ||
return 0 | ||
return EvalEnum.FREE_LINE.value | ||
|
||
@staticmethod | ||
def get_free_line_eval(board: 'Board', start_square: int) -> int: | ||
""" | ||
Method used to get free lines evals | ||
:param board: Board instance | ||
:param start_square: int starting square of a rook | ||
:return: int | ||
""" | ||
horizontal_eval: int = RookEval.get_horizontal_eval(start_square, board) | ||
vertical_eval: int = RookEval.get_vertical_eval(start_square, board) | ||
|
||
return horizontal_eval + vertical_eval |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
from game_window.enums.EvalEnum import EvalEnum | ||
from game_window.enums.PiecesEnum import PiecesEnum | ||
|
||
if TYPE_CHECKING: | ||
from game_window.Board import Board | ||
|
||
|
||
class StaticEvalUtil: | ||
@staticmethod | ||
def return_proper_evaluation_signed_value(board: 'Board', evaluation: int, favor_color: int) -> int: | ||
""" | ||
Method used to return a proper mark of evaluation based on favor_color to move | ||
:param favor_color: | ||
:param board: Board instance | ||
:param evaluation: int value of evaluation | ||
:return: int value with proper sign | ||
""" | ||
return evaluation if favor_color == board.get_engine_color() else -evaluation | ||
|
||
@staticmethod | ||
def is_queen_on_start_position(color: int, board: 'Board') -> bool: | ||
""" | ||
Method used to check if queen is on starting position | ||
:param color: int vale of color | ||
:param board: Board instance | ||
:return: bool | ||
""" | ||
start_positions = { | ||
board.get_engine_color(): 3, | ||
board.get_player_color(): 59 | ||
} | ||
|
||
for square, piece in enumerate(board.get_board_array()): | ||
if piece == color | PiecesEnum.QUEEN.value and start_positions[color] == square: | ||
return True | ||
return False | ||
|
||
@staticmethod | ||
def get_piece_point_value(piece_value: int) -> int: | ||
""" | ||
Method used to get proper eval value of a piece | ||
:param piece_value: int value of piece | ||
:return: int value of piece eval | ||
""" | ||
pieces_dict = { | ||
PiecesEnum.KNIGHT.value: EvalEnum.KNIGHT.value, | ||
PiecesEnum.BISHOP.value: EvalEnum.BISHOP.value, | ||
PiecesEnum.ROOK.value: EvalEnum.ROOK.value, | ||
PiecesEnum.QUEEN.value: EvalEnum.QUEEN.value, | ||
PiecesEnum.PAWN.value: EvalEnum.PAWN.value, | ||
PiecesEnum.KING.value: EvalEnum.KING.value | ||
} | ||
return pieces_dict[piece_value] |
90 changes: 90 additions & 0 deletions
90
src/main/game_window/engine/static_eval/StaticEvaluator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
from numba import jit | ||
from numpy import ndarray | ||
|
||
from game_window.ColorManager import ColorManager | ||
from game_window.engine.static_eval.KingPressure import KingPressure | ||
from game_window.engine.static_eval.LightPiecesEval import LightPiecesEval | ||
from game_window.engine.static_eval.PawnEval import PawnEval | ||
from game_window.engine.static_eval.RookEval import RookEval | ||
from game_window.engine.static_eval.StaticEvalUtil import StaticEvalUtil | ||
from game_window.enums.BoardEnum import BoardEnum | ||
from game_window.enums.EvalEnum import EvalEnum | ||
from game_window.enums.PiecesEnum import PiecesEnum | ||
|
||
if TYPE_CHECKING: | ||
from game_window.Board import Board | ||
|
||
|
||
class StaticEvaluator: | ||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_static_position(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to return an evaluation of starting position | ||
:param board: Board instance | ||
:param favor_color: int value of color in favor of which we evaluate position | ||
:return: int evaluation | ||
""" | ||
material_eval = StaticEvaluator.evaluate_pieces_on_board(board, favor_color) | ||
center_possession_eval = StaticEvaluator.evaluate_center_possession(board, favor_color) | ||
light_dev_eval = LightPiecesEval.evaluate_light_pieces_walked(board, favor_color) | ||
king_pressure = KingPressure.evaluate_king_pressure(board, favor_color) | ||
bishops = LightPiecesEval.evaluate_bishops(board, favor_color) | ||
free_lines = RookEval.evaluate_free_lines_for_rooks(board, favor_color) | ||
chains = PawnEval.evaluate_pawn_chains(board, favor_color) | ||
|
||
static_eval = material_eval + center_possession_eval + light_dev_eval + king_pressure + free_lines + bishops | ||
static_eval += chains | ||
|
||
return static_eval | ||
|
||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_pieces_on_board(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to sum value of pieces on board and return this sum as evaluation | ||
:param favor_color: | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
evaluation: int = 0 | ||
board_array: ndarray[int] = board.get_board_array() | ||
|
||
for square in board_array: | ||
if square == 0: | ||
continue | ||
pieces_color: int = ColorManager.get_piece_color(square) | ||
piece_value: int = square - pieces_color | ||
points: int = StaticEvalUtil.get_piece_point_value(piece_value) | ||
|
||
evaluation += points if pieces_color == board.get_engine_color() else -points | ||
return StaticEvalUtil.return_proper_evaluation_signed_value(board, evaluation, favor_color) | ||
|
||
@staticmethod | ||
@jit(forceobj=True) | ||
def evaluate_center_possession(board: 'Board', favor_color: int) -> int: | ||
""" | ||
Method used to evaluate a center possession | ||
:param favor_color: int value of color | ||
:param board: Board instance | ||
:return: int value of evaluation | ||
""" | ||
evaluation: int = 0 | ||
board_array: ndarray[int] = board.get_board_array() | ||
|
||
for center_square in BoardEnum.CENTER_SQUARES.value: | ||
piece: int = board_array[center_square] | ||
|
||
if piece == PiecesEnum.NONE.value: | ||
continue | ||
piece_color: int = ColorManager.get_piece_color(piece) | ||
|
||
if center_square in BoardEnum.CENTER_SIDE_SQUARES.value: | ||
evaluation += StaticEvalUtil.return_proper_evaluation_signed_value(board, EvalEnum.SIDE_CENTER.value, | ||
piece_color) | ||
if center_square in BoardEnum.CENTER_MAIN_SQUARES.value: | ||
evaluation += StaticEvalUtil.return_proper_evaluation_signed_value(board, EvalEnum.MAIN_CENTER.value, | ||
piece_color) | ||
return StaticEvalUtil.return_proper_evaluation_signed_value(board, evaluation, favor_color) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters