Емилиан обнови решението на 23.11.2022 21:43 (преди почти 2 години)
Предполагам, че ако дефинираш само малки или само главни бувки, после можеш лесно да ги сравняваш с str.lower()
и str.upper()
. Това е само предложение, за да няма дублиране на дефиниции, както тук, така и на ред 16.
Наследяване от BaseException
работи, но е против препоръките на Python.
Причината е, че специалните изключения като KeyboardInterrupt
наследяват BaseException
и ако искаш да хванеш такъв Exception
, маскираш KeyboardInterrupt
и един вид губиш функционалност. Всички къстъм изключения трябва да наследяват Exception
.
Можеш да си спестиш i
, ако използваш enumerate
в първия for
.
white_kings == 0 or white_kings > 1
== white_kings != 1
Би могъл да спестиш тези дефиниции, ако направиш обратното - да изчислиш разстоянието между двата царя и да провериш дали е 0/1. Няма проблем с тази имплементация, освен, че е дълга и лесно може да се сгреши при писане и преправяне.
Избягвай пренасяне на редове с наклонена черта. Специално за това има стандарт за форматиране: https://peps.python.org/pep-0008/#multiline-if-statements
Тази проверка е базирана на 7 реда. Губиш един ред в проверката си.
Ако си извикал функцията с невалиден цар, по-скоро бих хвърлил грешка. Връщайки празен стринг, замаскираш потенциален проблем, който ще се манифестира по-късно, но вече няма да е ясна причината.
По-скоро бих хвърлил грешка.
По дефиниция този тип методи трябва да връщат ChessScore
обект.
Имаш __int__
, така че не ти трябва метода get_total_score
. int(other)
ще даде същия резултат.
WHITE_KING = "K" BLACK_KING = "k" WHITE_PAWN = "P" BLACK_PAWN = "p" CHESS_COLUMN_TO_NUMERICAL = { "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "H": 8, }
FIGURE_TO_POINTS = { "r": 5, "n": 3, "b": 3, "q": 9, "k": 4, "p": 1, "R": 5, "N": 3, "B": 3, "Q": 9, "K": 4, "P": 1, }
class ChessException(Exception): pass
class ChessPosition: def init(self, fen_board: str = ""): self._set_fen_board(fen_board)
def _set_fen_board(self, fen_board):
self._original_fen = fen_board
self._create_board(fen_board)
self._check_for_neighboring_kings(self._board)
self._check_for_correct_kings(self._board)
self._check_for_incorrect_pawns(self._board)
self._set_points(self._board)
self._set_figures(self._board)
def _set_figures(self, board):
self._figures = []
for row in board:
for cell in row:
if cell in FIGURE_TO_POINTS:
self._figures.append(cell)
def _set_points(self, board):
white_figures = []
black_figures = []
for row in board:
for cell in row:
if cell is not None and cell.isupper():
white_figures.append(cell)
elif cell is not None and cell.islower():
black_figures.append(cell)
self._white_score = ChessScore(white_figures)
self._black_score = ChessScore(black_figures)
def _create_board(self, fen_board):
self._board = [[None for _ in range(8)] for _ in range(8)]
j = 0
for i, row in enumerate(fen_board.split("/")):
for cell in row:
if cell.isdigit():
for _ in range(int(cell)):
j += 1
else:
self._board[i][j] = cell
j += 1
j = 0
def _check_for_neighboring_kings(self, board):
for i, row in enumerate(board):
for j, cell in enumerate(row):
if cell == BLACK_KING or cell == WHITE_KING:
self._check_neighboring_squares((i, j))
def _check_for_correct_kings(self, board):
white_kings = 0
black_kings = 0
for _, row in enumerate(board):
for _, cell in enumerate(row):
if cell == BLACK_KING:
black_kings += 1
elif cell == WHITE_KING:
white_kings += 1
if white_kings != 1 or black_kings != 1:
raise ChessException("kings")
def _check_for_incorrect_pawns(self, board):
if (BLACK_PAWN in board[0]
or WHITE_PAWN in board[0]
or BLACK_PAWN in board[-1]
or WHITE_PAWN in board[-1]):
raise ChessException("pawns")
def _check_neighboring_squares(self, position: tuple[int, int]):
neighbouring_positions = [
(position[0] - 1, position[1] - 1),
(position[0] - 1, position[1]),
(position[0], position[1] - 1),
(position[0], position[1] + 1),
(position[0] + 1, position[1]),
(position[0] - 1, position[1] + 1),
(position[0] + 1, position[1] - 1),
(position[0] + 1, position[1] + 1),
]
current_king = self._board[position[0]][position[1]]
opposite_king = self._get_opposite_king(current_king)
for nb in neighbouring_positions:
if (self._is_in_board(nb)
and self._board[nb[0]][nb[1]] == opposite_king):
raise ChessException("kings")
def _is_in_board(self, position: tuple[int, int]):
return (position[0] >= 0
and position[0] <= 7
and position[1] >= 0
and position[1] <= 7)
def _get_opposite_king(self, king):
if king == BLACK_KING:
return WHITE_KING
elif king == WHITE_KING:
return BLACK_KING
raise ValueError("Invalid king provided")
def __len__(self):
return len(self._figures)
def __repr__(self):
return self._original_fen
def __str__(self):
return self._original_fen
def __setitem__(self, key, item):
self.__dict__[key] = item
def __getitem__(self, key):
if len(key) != 2 or key[0] not in CHESS_COLUMN_TO_NUMERICAL:
raise ValueError("Invalid position provided")
row = int(key[1])
col = int(CHESS_COLUMN_TO_NUMERICAL[key[0]])
return self._board[row][col]
def get_white_score(self):
return self._white_score
def get_black_score(self):
return self._black_score
def white_is_winning(self):
return self._black_score < self._white_score
def black_is_winning(self):
return self._black_score > self._white_score
def is_equal(self):
return self._black_score == self._white_score
class ChessScore: def init(self, pieces: list[str] = None): self._set_score(pieces)
def _set_score(self, pieces: list[str] = None):
self._total = 0
for piece in pieces:
if piece in pieces:
self._total += FIGURE_TO_POINTS[piece]
def __int__(self):
return self._total
def __lt__(self, other):
return self._total < int(other)
def __le__(self, other):
return self._total <= int(other)
def __ge__(self, other):
return self._total >= int(other)
def __eq__(self, other):
return self._total == int(other)
def __gt__(self, other):
return self._total > int(other)
def __add__(self, other):
return self._total + int(other)
def __sub__(self, other):
return self._total - int(other)
Предполагам, че ако дефинираш само малки или само главни бувки, после можеш лесно да ги сравняваш с
str.lower()
иstr.upper()
. Това е само предложение, за да няма дублиране на дефиниции, както тук, така и на ред 16.Би могъл да спестиш тези дефиниции, ако направиш обратното - да изчислиш разстоянието между двата царя и да провериш дали е 0/1. Няма проблем с тази имплементация, освен, че е дълга и лесно може да се сгреши при писане и преправяне.
Ако си извикал функцията с невалиден цар, по-скоро бих хвърлил грешка. Връщайки празен стринг, замаскираш потенциален проблем, който ще се манифестира по-късно, но вече няма да е ясна причината.