Александър обнови решението на 29.11.2022 00:04 (преди почти 2 години)
+
+ROWS = [8, 7, 6, 5, 4, 3, 2, 1]
+COLUMNS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+
+PIECE_CODE = {
+ 'rook': 'r',
+ 'knight': 'n',
+ 'bishop': 'b',
+ 'queen': 'q',
+ 'king': 'k',
+ 'pawn': 'p',
+ 'empty': '_'
+}
+
+PIECE_POINTS = {
+ 'r': 5,
+ 'n': 3,
+ 'b': 3,
+ 'q': 9,
+ 'k': 4,
+ 'p': 1
+}
+
+
+class ChessException(Exception):
+ pass
+
+
+class ChessScore():
+ def __init__(self, pieces: list[str]) -> None:
+ self._pieces = pieces
+ self._points = self._get_points_from_pieces(pieces)
+
+ def _get_points_from_pieces(self, pieces: list[str]):
+ points = 0
+ for piece in pieces:
+ points += PIECE_POINTS.get(piece, 0)
+ return points
+
+ def __int__(self):
+ return self._points
+
+ def __lt__(self, other):
+ return self._points < other._points
+
+ def __le__(self, other):
+ return self._points <= other._points
+
+ def __gt__(self, other):
+ return self._points > other._points
+
+ def __ge__(self, other):
+ return self._points >= other._points
+
+ def __eq__(self, other: object) -> bool:
+ return self._points == other._points
+
+ def __ne__(self, other: object) -> bool:
+ return self._points != other._points
+
+ def __add__(self, other):
+ return self._points + other._points
+
+ def __radd__(self, other):
+ return self.__add__(other)
+
+ def __sub__(self, other):
+ return self._points - other._points
+
+ def __rsub__(self, other):
+ return self.__sub__(other)
+
+
+class ChessPosition():
+ def __init__(self, FEN: str) -> None:
+ self._fill_matrix(FEN)
+ self._check_kings_one_on_one()
+ self._check_two_kings_neighbors()
+ self._check_pawns_impossible_positions()
+ self._FEN = FEN
+
+ def _fill_matrix(self, FEN: str):
+ # self._matrix = [[None for col in range(len(COLUMNS))] for row in range(len(ROWS))]
+ self._matrix = []
+ FEN_split = FEN.split('/')
+ for row in range(0, len(FEN_split)): # = ROWS, 8 -> 1
+ self._matrix.append([])
+ row_data = list(FEN_split[row])
+ for ch in row_data:
+ if ch.isdigit() and int(ch) in range(1, len(COLUMNS)+1):
+ for _ in range(int(ch)):
+ self._matrix[-1].append(PIECE_CODE['empty'])
+ elif ch.lower() in PIECE_CODE.values():
+ self._matrix[-1].append(ch)
+
+ def _check_kings_one_on_one(self):
+ white_kings = 0
+ black_kings = 0
+ for i in range(len(self._matrix)):
+ for j in range(len(self._matrix[i])):
+ if self._matrix[i][j] == PIECE_CODE['king'].lower():
+ white_kings += 1
+ elif self._matrix[i][j] == PIECE_CODE['king'].upper():
+ black_kings += 1
+ if black_kings != 1 or white_kings != 1:
+ raise ChessException("kings")
+
+ def _check_two_kings_neighbors(self):
+ # The _check_kings_one_on_one() checking is before this, so we can use that
Чудесен коментар! Поради точно тези причини, можеш да вземеш координатите на двата царя, след което да изчислиш разстоянието между тях, което ще направи кодът по-долу доста по-компактен.
+ # to our advantage here - we only need to see if two kings are neighbors,
+ # without having to check what their respective colors are - this is already done
+ # in the previous step.
+ for i in range(len(self._matrix)):
+ for j in range(len(self._matrix[i])):
+ if i < len(self._matrix) - 1 \
Избягвай да разделяш редовете с наклонена черта на всяка цена. В конкретният случай ще работи дори и без тях, защото използваш and
.
+ and self._matrix[i][j].lower() == PIECE_CODE['king'] \
+ and self._matrix[i+1][j].lower() == PIECE_CODE['king']:
+ raise ChessException("kings")
+
+ elif j < len(self._matrix[i]) - 1 \
+ and self._matrix[i][j].lower() == PIECE_CODE['king'] \
+ and self._matrix[i][j+1].lower() == PIECE_CODE['king']:
+ raise ChessException("kings")
+
+ elif i < len(self._matrix) - 1 and j < len(self._matrix[i]) - 1 \
+ and self._matrix[i][j].lower() == PIECE_CODE['king'] \
+ and self._matrix[i+1][j+1].lower() == PIECE_CODE['king']:
+ raise ChessException("kings")
+
+ elif i < len(self._matrix) - 1 and j >= 1 \
+ and self._matrix[i][j].lower() == PIECE_CODE['king'] \
+ and self._matrix[i+1][j-1].lower() == PIECE_CODE['king']:
+ raise ChessException("kings")
+
+ def _check_pawns_impossible_positions(self):
+ for i in range(len(self._matrix)):
+ for j in range(len(self._matrix[i])):
+ if i in [0, len(ROWS)-1] and self._matrix[i][j].lower() == PIECE_CODE['pawn']:
+ raise ChessException("pawns")
+
+ def get_white_score(self) -> ChessScore:
+ return ChessScore([piece.lower() for piece in self._FEN if piece != '/'
+ and not piece.isdigit()
+ and piece.isupper()])
+
+ def get_black_score(self) -> ChessScore:
+ return ChessScore([piece for piece in self._FEN if piece != '/'
+ and not piece.isdigit()
+ and piece.islower()])
+
+ def white_is_winning(self) -> bool:
+ return self.get_white_score() > self.get_black_score()
+
+ def black_is_winning(self) -> bool:
+ return self.get_white_score() < self.get_black_score()
+
+ def is_equal(self) -> bool:
+ return self.get_white_score() == self.get_black_score()
+
+ def __str__(self) -> str:
+ return ''.join(self._FEN)
+
+ def __repr__(self) -> str:
+ return ''.join(self._FEN)
+
+ def __len__(self):
+ return len([piece for piece in self._FEN if piece != '/' and not piece.isdigit()])
+
+ def __getitem__(self, key: str):
+ row = int(key[1])
+ col = key[0]
+
+ matrix_row = 0
Тук просто обръщаш реда, нали? Защо не просто 8-row
? Може би осмицата ще е добре да се вземе динамично, а може да изпускам и гранична стойност, но определено нещо подобно би било по-лесно.
+ for _ in range(ROWS[0], row, -1):
+ matrix_row += 1
+
+ matrix_col = 0
+ for _ in range(ord(COLUMNS[0]), ord(col)):
Не можеш ли просто да вземеш разликата от ord(col)
и ord(COLUMNS[0])
?
+ matrix_col += 1
+
+ return self._matrix[matrix_row][matrix_col] if self._matrix[matrix_row][matrix_col] != '_' else None
+
+
+# POSITION
+'''
+# c = ChessPosition("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR")
+# c = ChessPosition("rnbqbknr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR") # eq
+c = ChessPosition("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR")
+# c = ChessPosition("8/8/8/8/4P3/8/8/qqqqqqqq/8")
+# c = ChessPosition("rnbqkbKn/pppppppp/8/8/8/8/8/RNBQBBNR")
+print(c._matrix)
+
+print(int(c.get_white_score()))
+print(int(c.get_black_score()))
+print(c.white_is_winning())
+print(c.black_is_winning())
+print(c.is_equal())
+
+print(c)
+print(len(c))
+print(c['E1'])
+print()
+'''
+
+
+# SCORE
+'''
+s1 = ChessScore("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR")
+s2 = ChessScore("rnbqkbnr/pppppppp/4KK2/rnbbbbb")
+s3 = ChessScore("rnbqkbnr/pppppppp/4KK2/rnbbbbb$wetyicv39634890_ ///40/cvcljhgfds';.,m986635242")
+print(int(s1))
+print(int(s2))
+print(int(s3))
+print(s1 < s2)
+print(s1 <= s2)
+print(s1 == s2)
+print(s1 != s2)
+print(s1 > s2)
+print(s1 + s2)
+print(s1 - s2)
+'''
Имах няколко препоръки, но като цяло кодът ти е доста ясен и чист, затова получаваш бонус точка.
Чудесен коментар! Поради точно тези причини, можеш да вземеш координатите на двата царя, след което да изчислиш разстоянието между тях, което ще направи кодът по-долу доста по-компактен.
Избягвай да разделяш редовете с наклонена черта на всяка цена. В конкретният случай ще работи дори и без тях, защото използваш
and
.Тук просто обръщаш реда, нали? Защо не просто
8-row
? Може би осмицата ще е добре да се вземе динамично, а може да изпускам и гранична стойност, но определено нещо подобно би било по-лесно.Не можеш ли просто да вземеш разликата от
ord(col)
иord(COLUMNS[0])
?