Георги обнови решението на 18.11.2022 00:31 (преди около 2 години)
+import random
+
+
+class ChessException(Exception):
+ pass
+
+
+class ChessScore:
+ """Represent the score associated with a set of Chess pieces."""
+
+ SCORES = {'r': 5,
+ 'n': 3,
+ 'b': 3,
+ 'k': 4,
+ 'q': 9,
+ 'p': 1}
+
+ def __init__(self, pieces):
+ """Initializator."""
+ self._pieces = pieces
+ self._score = 0
+ self._calculate_score()
+
+ @staticmethod
+ def __type_checked(fun):
+ """Decorator for type checking in other methods."""
+ def decorated(this, other):
+ if type(this) is not type(other):
+ raise TypeError("Invalid operation on "
+ f"{type(this)} and {type(other)}.")
+ return fun(this, other)
+ return decorated
+
+ def _calculate_score(self):
+ """Calculate score as number."""
+ for piece in self._pieces:
+ # KeyErrors just get propagated
+ self._score += self.SCORES[piece]
+
+ def __int__(self):
+ """Integer representation."""
+ return self._score
+
+ @__type_checked
+ def __eq__(self, other):
+ """Equal comparison."""
+ return self._score == other._score
+
+ @__type_checked
+ def __lt__(self, other):
+ """Less than comparison."""
+ return self._score < other._score
+
+ @__type_checked
+ def __gt__(self, other):
+ """Greater than comparison."""
+ return self._score > other._score
+
+ @__type_checked
+ def __le__(self, other):
+ """Less or equal comparison."""
+ return self._score <= other._score
+
+ @__type_checked
+ def __ge__(self, other):
+ """Creater or equal comparison."""
+ return self._score >= other._score
+
+ @__type_checked
+ def __add__(self, other):
+ """Sum of two scores."""
+ return self._score + other._score
+
+ @__type_checked
+ def __sub__(self, other):
+ """Subtraction of two scores."""
+ return self._score - other._score
+
+
+class ChessPosition:
+ """Represent a Chess position."""
+
+ COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+
+ def __init__(self, fen):
+ """Initializator."""
+ self._fen = fen
+ self._parsed = {}
+ self._white_score = self._assign_score(str.isupper)
+ self._black_score = self._assign_score(str.islower)
+ self._parse_fen()
+ self._validate()
+
+ def _parse_fen(self):
+ """Parse fen into easy to use dictionary."""
+ for row, row_label in zip(self._fen.split('/')[::-1], range(1, 9)):
+ self._parsed[row_label] = {}
+ col_index = 0
+ for square in row:
+ if square.isdigit():
+ for _ in range(int(square)):
+ self._parsed[row_label][self.COLS[col_index]] = None
+ col_index += 1
+ else:
+ self._parsed[row_label][self.COLS[col_index]] = square
+ col_index += 1
+
+ def _validate(self):
+ """Validate the input fen."""
+ self._validate_king_count()
+ self._validate_king_position()
+ self._validate_pawns_position()
+
+ def _validate_king_count(self):
+ """Validate correct number of kings."""
+ if self._fen.count('k') != 1 or self._fen.count('K') != 1:
+ raise ChessException('kings')
+
+ def _validate_king_position(self):
+ """Validate correct position of kings."""
+ positions = {'k': None, 'K': None}
+ for row_index, (row_label, row) in enumerate(self._parsed.items()):
+ for col_index, (col_label, square) in enumerate(row.items()):
+ if square and square.lower() == 'k':
+ positions[square] = (row_index, col_index)
+ offset_x = abs(positions['K'][1] - positions['k'][1])
+ offset_y = abs(positions['K'][0] - positions['k'][0])
+ if offset_x in (0, 1) and offset_y in (0, 1):
+ raise ChessException('kings')
+
+ def _validate_pawns_position(self):
+ """Validate correct position of pawns."""
+ rows = list(self._parsed[1].values()) + list(self._parsed[8].values())
+ if 'p' in rows or 'P' in rows:
+ raise ChessException('pawns')
+
+ def _assign_score(self, filter_fun):
+ """Assign a ChessScore instance for particular type of pieces."""
+ return ChessScore(list(map(str.lower, filter(filter_fun, self._fen))))
+
+ def get_white_score(self):
+ """Return white score object."""
+ return self._white_score
+
+ def get_black_score(self):
+ """Return black score object."""
+ return self._black_score
+
+ def white_is_winning(self):
+ """Return bool of whether white is winning."""
+ return self._white_score > self._black_score
+
+ def black_is_winning(self):
+ """Return bool of whether black is winning."""
+ return self._black_score > self._white_score
+
+ def is_equal(self):
+ """Return bool of whether the game is equal."""
+ return self._black_score == self._white_score
+
+ def __str__(self):
+ """String representation of the position."""
+ return self._fen
+
+ def __len__(self):
+ """Number of pieces in the position."""
+ return len(list(filter(str.isalpha, self._fen)))
+
+ def __getitem__(self, coordinates):
+ """Get a piece from coordinates."""
+ col, row = coordinates[0], coordinates[1]
+ return self._parsed[int(row)][col]