Решение на Шахматни фенове от Александър Сариков

Обратно към всички решения

Към профила на Александър Сариков

Резултати

  • 10 точки от тестове
  • 1 бонус точка
  • 11 точки общо
  • 17 успешни тест(а)
  • 0 неуспешни тест(а)

Код

BOARD_COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
POINTS_PER_PIECE = {'r': 5, 'n': 3, 'b': 3, 'q': 9, 'k': 4, 'p': 1}
class ChessException(Exception):
"""Custom exception class for chess games."""
pass
class ChessPosition:
"""Represents chess position in FEN(Forsyth-Edwards Notation)."""
def __init__(self, fen):
"""Initialize"""
self.fen = fen
self._board = []
self._populate_chess_board()
self._validate_kings_count()
self._validate_kings_neighbours()
self._validate_pawns_positions()
def _populate_chess_board(self):
"""Create 2D matrix representing a chess board and populate it with pieces."""
rows = self.fen.split('/')
if len(rows) != len(BOARD_COLS):
raise ChessException('Invalid board dimensions!')
for i, row in enumerate(rows):
self._board.append([])
for character in row:
if character.lower() in POINTS_PER_PIECE.keys():
self._board[i].append(character)
elif character.isdigit() and int(character) in range(9):
self._board[i].extend([None] * int(character))
else: # If invalid character - not specified what should happen
self._board[i].append(character)
def _validate_kings_neighbours(self):
"""Validate that both kings are not in close proximity of each other. Otherwise - raise ChessException."""
for i, row in enumerate(self._board):
for j, col_value in enumerate(row):
if col_value == 'k':
black_king_coords = i, j
elif col_value == 'K':
white_king_coords = i, j
# If the black king is a neighbour to the white king so is the white one to the black one.
# The case of having more or less than 2 kings is already handled by __validate_kings_count so we don't need more checks.
if abs(white_king_coords[0] - black_king_coords[0]) <= 1 and abs(white_king_coords[1] - black_king_coords[1]) <= 1:
raise ChessException('kings')
def _validate_kings_count(self):
"""Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
if self.fen.count('k') != 1 or self.fen.count('K') != 1:
raise ChessException('kings')
def _validate_pawns_positions(self):
"""Validate that there are no pawn pieces on the first and last row. Otherwise - raise ChessException."""
rows = self.fen.split('/')
if 'p' in rows[0].lower() or 'p' in rows[-1].lower():
raise ChessException('pawns')
def get_white_score(self):
"""Return a ChessScore object representing the total score of all white pieces."""
return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.fen)))
def get_black_score(self):
"""Return a ChessScore object representing the total score of all black pieces."""
return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.fen)))
def white_is_winning(self):
"""Check if the total score of the white pieces is greater than the total score of the black pieces."""
return self.get_white_score() > self.get_black_score()
def black_is_winning(self):
"""Check if the total score of the white pieces is less than the total score of the black pieces."""
return self.get_white_score() < self.get_black_score()
def is_equal(self):
"""Check if the total score of the white pieces is equal to the total score of the black pieces."""
return self.get_white_score() == self.get_black_score()
def __str__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.fen
def __repr__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.fen
def __len__(self):
"""Return the the total number of pieces in this ChessPosition."""
length = 0
for piece in POINTS_PER_PIECE.keys():
length += self.fen.count(piece)
length += self.fen.count(piece.upper())
return length
def __getitem__(self, coords):
"""Allow indexation of the object by supplying board coordinates in Algebraic notation (e.g. 'A1') as string argument."""
if len(coords) != 2:
return
if coords[0].upper() in BOARD_COLS and coords[1].isdigit() and int(coords[1]) in range(1, len(BOARD_COLS) + 1):
return self._board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())]
else:
return
class ChessScore:
"""Class representing the total score of all supplied chess pieces."""
def __init__(self, pieces):
"""Initialize"""
self._pieces = [piece.lower() for piece in pieces]
def __int__(self):
"""Specify behaviour when object is called with the built-in 'int()' function."""
score = 0
for piece, points in POINTS_PER_PIECE.items():
score += self._pieces.count(piece) * points
return score
def __lt__(self, other):
"""Define functionality of '<' (less than) operator."""
return int(self) < int(other)
def __le__(self, other):
"""Define functionality of '<=' (less than or equal to) operator."""
return int(self) <= int(other)
def __eq__(self, other):
"""Define functionality of '==' (equality) operator."""
return int(self) == int(other)
def __ne__(self, other):
"""Define functionality of '!=' (not equal to) operator."""
return int(self) != int(other)
def __gt__(self, other):
"""Define functionality of '>' (greater than) operator."""
return int(self) > int(other)
def __ge__(self, other):
"""Define functionality of '>=' (greater than or equal to) operator."""
return int(self) >= int(other)
def __add__(self, other):
"""Define functionality of '+' operator between ChessScore object and other object."""
return int(self) + int(other)
def __sub__(self, other):
"""Define functionality of '-' operator between ChessScore object and other object."""
return int(self) - int(other)
# Potentially unnecessary
def __str__(self):
"""Return the object representation in string format."""
return str(int(self))
def __repr__(self):
"""Return the object representation in string format."""
return str(int(self))

Лог от изпълнението

.................
----------------------------------------------------------------------
Ran 17 tests in 0.165s

OK

История (4 версии и 9 коментара)

Александър обнови решението на 23.11.2022 13:42 (преди почти 2 години)

+import re
+
+
+BOARD_COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+
+POINTS_PER_PIECE = {'r': 5, 'n': 3, 'b': 3, 'q': 9, 'k': 4, 'p': 1}
+
+
+class ChessException(Exception):
+ """Custom exception class."""
+
+ # Премахва '__main__.' в output-a пред името на exception-a.
+ # (пример: 'ChessException: kings' вместо '__main__.ChessException: kings')
+ # Не съм сигурен кой е очакваният резултат.
+ __module__ = Exception.__module__
+
+ def __init__(self, message):
+ """Initialize"""
+ super().__init__(message)
+
+
+class ChessPosition:
+ """Represents chess position in FEN(Forsyth-Edwards Notation)."""
+
+ def __init__(self, FEN):
+ """Initialize"""
+ self.FEN = FEN
+ self.__board = []
+ self.__populate_chess_board()
+ self.__validate_kings_count()
+ self.__validate_kings_neighbours()
+ self.__validate_pawns_positions()
+
+ def __populate_chess_board(self):
+ """Create 2D matrix representing a chess board and populate it with pieces."""
+ rows = self.FEN.split('/')
+
+ # Expect that the size of the board is always 8x8
+ if len(rows) != len(BOARD_COLS):
+ # Error message not specified so maybe unnecessary?
+ raise ChessException('Invalid board dimensions!')
+
+ for i, row in enumerate(rows):
+ self.__board.append([])
+ for character in row:
+ if character.lower() in POINTS_PER_PIECE.keys():
+ self.__board[i].append(character)
+ elif character.isdigit() and int(character) in range(9):
+ self.__board[i].extend([None] * int(character))
+ else: # If invalid character - not specified what to do
+ self.__board[i].append(character)
+
+ def __validate_kings_neighbours(self):
+ """Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
+ black_king_coords = -2, -2
+ white_king_coords = -2, -2
+
+ for i, row in enumerate(self.__board):
+ for j, col_value in enumerate(row):
+ if col_value == 'k':
+ black_king_coords = i, j
+ elif col_value == 'K':
+ white_king_coords = i, j
+
+ # If the black king is a neighbour to the white king so is the white one to the black one.
+ # The case of having more than 2 kings is already handled by __validate_kings_count so we don't need more checks.
+ if white_king_coords[0] - 1 <= black_king_coords[0] <= white_king_coords[0] + 1 and \
+ white_king_coords[1] - 1 <= black_king_coords[1] <= white_king_coords[1] + 1:
+ raise ChessException('kings')
+
+ def __validate_kings_count(self):
+ """Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
+ if len(re.findall('k', self.FEN)) != 1 or len(re.findall('K', self.FEN)) != 1:
+ raise ChessException('kings')
+
+ # Assuming that pawn always gets promoted to other piece even if it is on the opposite side's last row
+ def __validate_pawns_positions(self):
+ """Validate that there are no pawn pieces on row 1 and 8 of the chess board. Otherwise - raise ChessException."""
+ rows = self.FEN.split('/')
+ if re.search('[pP]', rows[0]) or re.search('[pP]', rows[len(rows) - 1]):
+ raise ChessException('pawns')
+
+ def get_white_score(self):
+ """Return a ChessScore object representing the total score of all white pieces."""
+ return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.FEN)))
+
+ def get_black_score(self):
+ """Return a ChessScore object representing the total score of all black pieces."""
+ return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.FEN)))
+
+ def white_is_winning(self):
+ """Check if the total score of the white pieces is greater than the total score of the black pieces."""
+ return self.get_white_score() > self.get_black_score()
+
+ def black_is_winning(self):
+ """Check if the total score of the white pieces is less than the total score of the black pieces."""
+ return self.get_white_score() < self.get_black_score()
+
+ def is_equal(self):
+ """Check if the total score of the white pieces is equal to the total score of the black pieces."""
+ return self.get_white_score() == self.get_black_score()
+
+ def __str__(self):
+ """Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
+ return self.FEN
+
+ def __repr__(self):
+ """Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
+ return self.FEN
+
+ def __len__(self):
+ """Return the the total number of pieces in this ChessPosition."""
+ length = 0
+ for piece in POINTS_PER_PIECE.keys():
+ length += self.FEN.count(piece)
+ length += self.FEN.count(piece.upper())
+ return length
+
+ def __getitem__(self, coords):
+ """Allow indexation of the object by supplying board coordinates in Algebraic notation (ex. A1) as string argument."""
+ return self.__board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())] \
+ if len(coords) == 2 and coords[0].upper() in BOARD_COLS and coords[1].isdigit() and \
+ int(coords[1]) in range(1, len(BOARD_COLS) + 1) else None
+
+
+class ChessScore:
+ """Class representing the total score of all supplied chess pieces."""
+
+ # Не ми стана ясно дали (на обект от този клас) трябва да подавам списък като аргумент или множество аргументи.
+ # В описанието пише, че се подава list от str,
+ # а в примера под него пише, че при int(ChessScore('r', 'b')) връща 8, като очевидно са подадени 2 аргумента
+ def __init__(self, pieces):
+ """Initialize"""
+ self._pieces = [piece.lower() for piece in pieces]
+
+ def __int__(self):
+ """Specify behaviour when object is called with the built-in 'int()' function."""
+ result = 0
+ for piece, points in POINTS_PER_PIECE.items():
+ result += self._pieces.count(piece) * points
+ return result
+
+ def __lt__(self, other):
+ """Define functionality of '<' (less than) operator."""
+ return int(self) < int(other)
+
+ def __le__(self, other):
+ """Define functionality of '<=' (less than or equal to) operator."""
+ return int(self) <= int(other)
+
+ def __eq__(self, other):
+ """Define functionality of '==' (equality) operator."""
+ return int(self) == int(other)
+
+ def __ne__(self, other):
+ """Define functionality of '!=' (not equal to) operator."""
+ return int(self) != int(other)
+
+ def __gt__(self, other):
+ """Define functionality of '>' (greater than) operator."""
+ return int(self) > int(other)
+
+ def __ge__(self, other):
+ """Define functionality of '>=' (greater than or equal to) operator."""
+ return int(self) >= int(other)
+
+ def __add__(self, other):
+ """Define functionality of '+' operator between ChessScore object and other object."""
+ return int(self) + int(other)
+
+ def __sub__(self, other):
+ """Define functionality of '-' operator between ChessScore object and other object."""
+ return int(self) - int(other)
+
+ # Може би ненужни?
+ def __str__(self):
+ """Return the object representation in string format."""
+ return str(int(self))
+
+ def __repr__(self):
+ """Return the object representation in string format."""
+ return str(int(self))

Александър обнови решението на 23.11.2022 13:54 (преди почти 2 години)

import re
BOARD_COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
POINTS_PER_PIECE = {'r': 5, 'n': 3, 'b': 3, 'q': 9, 'k': 4, 'p': 1}
class ChessException(Exception):
"""Custom exception class."""
# Премахва '__main__.' в output-a пред името на exception-a.
# (пример: 'ChessException: kings' вместо '__main__.ChessException: kings')
# Не съм сигурен кой е очакваният резултат.
__module__ = Exception.__module__
def __init__(self, message):
"""Initialize"""
super().__init__(message)
class ChessPosition:
"""Represents chess position in FEN(Forsyth-Edwards Notation)."""
def __init__(self, FEN):
"""Initialize"""
self.FEN = FEN
self.__board = []
self.__populate_chess_board()
self.__validate_kings_count()
self.__validate_kings_neighbours()
self.__validate_pawns_positions()
def __populate_chess_board(self):
"""Create 2D matrix representing a chess board and populate it with pieces."""
rows = self.FEN.split('/')
# Expect that the size of the board is always 8x8
if len(rows) != len(BOARD_COLS):
# Error message not specified so maybe unnecessary?
raise ChessException('Invalid board dimensions!')
for i, row in enumerate(rows):
self.__board.append([])
for character in row:
if character.lower() in POINTS_PER_PIECE.keys():
self.__board[i].append(character)
elif character.isdigit() and int(character) in range(9):
self.__board[i].extend([None] * int(character))
else: # If invalid character - not specified what to do
self.__board[i].append(character)
def __validate_kings_neighbours(self):
- """Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
+ """Validate that both king are not in 1x1 proximity of each other. Otherwise - raise ChessException."""
black_king_coords = -2, -2
white_king_coords = -2, -2
for i, row in enumerate(self.__board):
for j, col_value in enumerate(row):
if col_value == 'k':
black_king_coords = i, j
elif col_value == 'K':
white_king_coords = i, j
# If the black king is a neighbour to the white king so is the white one to the black one.
# The case of having more than 2 kings is already handled by __validate_kings_count so we don't need more checks.
if white_king_coords[0] - 1 <= black_king_coords[0] <= white_king_coords[0] + 1 and \
white_king_coords[1] - 1 <= black_king_coords[1] <= white_king_coords[1] + 1:
raise ChessException('kings')
def __validate_kings_count(self):
"""Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
if len(re.findall('k', self.FEN)) != 1 or len(re.findall('K', self.FEN)) != 1:
raise ChessException('kings')
# Assuming that pawn always gets promoted to other piece even if it is on the opposite side's last row
def __validate_pawns_positions(self):
"""Validate that there are no pawn pieces on row 1 and 8 of the chess board. Otherwise - raise ChessException."""
rows = self.FEN.split('/')
if re.search('[pP]', rows[0]) or re.search('[pP]', rows[len(rows) - 1]):
raise ChessException('pawns')
def get_white_score(self):
"""Return a ChessScore object representing the total score of all white pieces."""
return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.FEN)))
def get_black_score(self):
"""Return a ChessScore object representing the total score of all black pieces."""
return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.FEN)))
def white_is_winning(self):
"""Check if the total score of the white pieces is greater than the total score of the black pieces."""
return self.get_white_score() > self.get_black_score()
def black_is_winning(self):
"""Check if the total score of the white pieces is less than the total score of the black pieces."""
return self.get_white_score() < self.get_black_score()
def is_equal(self):
"""Check if the total score of the white pieces is equal to the total score of the black pieces."""
return self.get_white_score() == self.get_black_score()
def __str__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.FEN
def __repr__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.FEN
def __len__(self):
"""Return the the total number of pieces in this ChessPosition."""
length = 0
for piece in POINTS_PER_PIECE.keys():
length += self.FEN.count(piece)
length += self.FEN.count(piece.upper())
return length
def __getitem__(self, coords):
"""Allow indexation of the object by supplying board coordinates in Algebraic notation (ex. A1) as string argument."""
return self.__board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())] \
if len(coords) == 2 and coords[0].upper() in BOARD_COLS and coords[1].isdigit() and \
int(coords[1]) in range(1, len(BOARD_COLS) + 1) else None
class ChessScore:
"""Class representing the total score of all supplied chess pieces."""
# Не ми стана ясно дали (на обект от този клас) трябва да подавам списък като аргумент или множество аргументи.
# В описанието пише, че се подава list от str,
# а в примера под него пише, че при int(ChessScore('r', 'b')) връща 8, като очевидно са подадени 2 аргумента
def __init__(self, pieces):
"""Initialize"""
self._pieces = [piece.lower() for piece in pieces]
def __int__(self):
"""Specify behaviour when object is called with the built-in 'int()' function."""
result = 0
for piece, points in POINTS_PER_PIECE.items():
result += self._pieces.count(piece) * points
return result
def __lt__(self, other):
"""Define functionality of '<' (less than) operator."""
return int(self) < int(other)
def __le__(self, other):
"""Define functionality of '<=' (less than or equal to) operator."""
return int(self) <= int(other)
def __eq__(self, other):
"""Define functionality of '==' (equality) operator."""
return int(self) == int(other)
def __ne__(self, other):
"""Define functionality of '!=' (not equal to) operator."""
return int(self) != int(other)
def __gt__(self, other):
"""Define functionality of '>' (greater than) operator."""
return int(self) > int(other)
def __ge__(self, other):
"""Define functionality of '>=' (greater than or equal to) operator."""
return int(self) >= int(other)
def __add__(self, other):
"""Define functionality of '+' operator between ChessScore object and other object."""
return int(self) + int(other)
def __sub__(self, other):
"""Define functionality of '-' operator between ChessScore object and other object."""
return int(self) - int(other)
# Може би ненужни?
def __str__(self):
"""Return the object representation in string format."""
return str(int(self))
def __repr__(self):
"""Return the object representation in string format."""
return str(int(self))

Александър обнови решението на 23.11.2022 14:09 (преди почти 2 години)

import re
BOARD_COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
POINTS_PER_PIECE = {'r': 5, 'n': 3, 'b': 3, 'q': 9, 'k': 4, 'p': 1}
class ChessException(Exception):
"""Custom exception class."""
# Премахва '__main__.' в output-a пред името на exception-a.
# (пример: 'ChessException: kings' вместо '__main__.ChessException: kings')
# Не съм сигурен кой е очакваният резултат.
__module__ = Exception.__module__
def __init__(self, message):
"""Initialize"""
super().__init__(message)
class ChessPosition:
"""Represents chess position in FEN(Forsyth-Edwards Notation)."""
def __init__(self, FEN):
"""Initialize"""
self.FEN = FEN
self.__board = []
self.__populate_chess_board()
self.__validate_kings_count()
self.__validate_kings_neighbours()
self.__validate_pawns_positions()
def __populate_chess_board(self):
"""Create 2D matrix representing a chess board and populate it with pieces."""
rows = self.FEN.split('/')
# Expect that the size of the board is always 8x8
if len(rows) != len(BOARD_COLS):
# Error message not specified so maybe unnecessary?
raise ChessException('Invalid board dimensions!')
for i, row in enumerate(rows):
self.__board.append([])
for character in row:
if character.lower() in POINTS_PER_PIECE.keys():
self.__board[i].append(character)
elif character.isdigit() and int(character) in range(9):
self.__board[i].extend([None] * int(character))
else: # If invalid character - not specified what to do
self.__board[i].append(character)
def __validate_kings_neighbours(self):
- """Validate that both king are not in 1x1 proximity of each other. Otherwise - raise ChessException."""
+ """Validate that both kings are not in 1x1 proximity of each other. Otherwise - raise ChessException."""
black_king_coords = -2, -2

Бих използвал None за тези дефиниции. Както сам си написал по-долу, вече сме сигурни, че има точно по един цар от двата цвята, така че дори не би трябвало да се притесняваме за тези два реда. Можеш да ги пропуснеш и да скочиш на циклите, които ще ги инициализират с правилни стойности.

white_king_coords = -2, -2
for i, row in enumerate(self.__board):
for j, col_value in enumerate(row):
if col_value == 'k':
black_king_coords = i, j
elif col_value == 'K':
white_king_coords = i, j
# If the black king is a neighbour to the white king so is the white one to the black one.
# The case of having more than 2 kings is already handled by __validate_kings_count so we don't need more checks.
if white_king_coords[0] - 1 <= black_king_coords[0] <= white_king_coords[0] + 1 and \
white_king_coords[1] - 1 <= black_king_coords[1] <= white_king_coords[1] + 1:
raise ChessException('kings')
def __validate_kings_count(self):
"""Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
if len(re.findall('k', self.FEN)) != 1 or len(re.findall('K', self.FEN)) != 1:
raise ChessException('kings')
- # Assuming that pawn always gets promoted to other piece even if it is on the opposite side's last row
+ # Assuming that pawn always gets promoted to other piece once it's on the opposite side's first row
def __validate_pawns_positions(self):
"""Validate that there are no pawn pieces on row 1 and 8 of the chess board. Otherwise - raise ChessException."""
rows = self.FEN.split('/')
- if re.search('[pP]', rows[0]) or re.search('[pP]', rows[len(rows) - 1]):
+ if re.search('[pP]', rows[0]) or re.search('[pP]', rows[-1]):
raise ChessException('pawns')
def get_white_score(self):
"""Return a ChessScore object representing the total score of all white pieces."""
return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.FEN)))
def get_black_score(self):
"""Return a ChessScore object representing the total score of all black pieces."""
return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.FEN)))
def white_is_winning(self):
"""Check if the total score of the white pieces is greater than the total score of the black pieces."""
return self.get_white_score() > self.get_black_score()
def black_is_winning(self):
"""Check if the total score of the white pieces is less than the total score of the black pieces."""
return self.get_white_score() < self.get_black_score()
def is_equal(self):
"""Check if the total score of the white pieces is equal to the total score of the black pieces."""
return self.get_white_score() == self.get_black_score()
def __str__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.FEN
def __repr__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
return self.FEN
def __len__(self):
"""Return the the total number of pieces in this ChessPosition."""
length = 0
for piece in POINTS_PER_PIECE.keys():
length += self.FEN.count(piece)
length += self.FEN.count(piece.upper())
return length
def __getitem__(self, coords):
"""Allow indexation of the object by supplying board coordinates in Algebraic notation (ex. A1) as string argument."""
return self.__board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())] \
if len(coords) == 2 and coords[0].upper() in BOARD_COLS and coords[1].isdigit() and \
int(coords[1]) in range(1, len(BOARD_COLS) + 1) else None
class ChessScore:
"""Class representing the total score of all supplied chess pieces."""
# Не ми стана ясно дали (на обект от този клас) трябва да подавам списък като аргумент или множество аргументи.
# В описанието пише, че се подава list от str,
# а в примера под него пише, че при int(ChessScore('r', 'b')) връща 8, като очевидно са подадени 2 аргумента
def __init__(self, pieces):
"""Initialize"""
self._pieces = [piece.lower() for piece in pieces]
def __int__(self):
"""Specify behaviour when object is called with the built-in 'int()' function."""
result = 0
for piece, points in POINTS_PER_PIECE.items():
result += self._pieces.count(piece) * points
return result
def __lt__(self, other):
"""Define functionality of '<' (less than) operator."""
return int(self) < int(other)
def __le__(self, other):
"""Define functionality of '<=' (less than or equal to) operator."""
return int(self) <= int(other)
def __eq__(self, other):
"""Define functionality of '==' (equality) operator."""
return int(self) == int(other)
def __ne__(self, other):
"""Define functionality of '!=' (not equal to) operator."""
return int(self) != int(other)
def __gt__(self, other):
"""Define functionality of '>' (greater than) operator."""
return int(self) > int(other)
def __ge__(self, other):
"""Define functionality of '>=' (greater than or equal to) operator."""
return int(self) >= int(other)
def __add__(self, other):
"""Define functionality of '+' operator between ChessScore object and other object."""
return int(self) + int(other)
def __sub__(self, other):
"""Define functionality of '-' operator between ChessScore object and other object."""
return int(self) - int(other)
# Може би ненужни?
def __str__(self):
"""Return the object representation in string format."""
return str(int(self))
def __repr__(self):
"""Return the object representation in string format."""
return str(int(self))

Александър обнови решението на 27.11.2022 13:43 (преди почти 2 години)

-import re
-
-
BOARD_COLS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
-
POINTS_PER_PIECE = {'r': 5, 'n': 3, 'b': 3, 'q': 9, 'k': 4, 'p': 1}
class ChessException(Exception):
- """Custom exception class."""
+ """Custom exception class for chess games."""
+ pass
- # Премахва '__main__.' в output-a пред името на exception-a.
- # (пример: 'ChessException: kings' вместо '__main__.ChessException: kings')
- # Не съм сигурен кой е очакваният резултат.
- __module__ = Exception.__module__
- def __init__(self, message):
- """Initialize"""
- super().__init__(message)
-
-
class ChessPosition:
"""Represents chess position in FEN(Forsyth-Edwards Notation)."""
- def __init__(self, FEN):
+ def __init__(self, fen):
"""Initialize"""
- self.FEN = FEN
- self.__board = []
- self.__populate_chess_board()
- self.__validate_kings_count()
- self.__validate_kings_neighbours()
- self.__validate_pawns_positions()
+ self.fen = fen
+ self._board = []
+ self._populate_chess_board()
+ self._validate_kings_count()
+ self._validate_kings_neighbours()
+ self._validate_pawns_positions()
- def __populate_chess_board(self):
+ def _populate_chess_board(self):
"""Create 2D matrix representing a chess board and populate it with pieces."""
- rows = self.FEN.split('/')
+ rows = self.fen.split('/')
- # Expect that the size of the board is always 8x8
if len(rows) != len(BOARD_COLS):
- # Error message not specified so maybe unnecessary?
raise ChessException('Invalid board dimensions!')
for i, row in enumerate(rows):
- self.__board.append([])
+ self._board.append([])
for character in row:
if character.lower() in POINTS_PER_PIECE.keys():
- self.__board[i].append(character)
+ self._board[i].append(character)
elif character.isdigit() and int(character) in range(9):
- self.__board[i].extend([None] * int(character))
- else: # If invalid character - not specified what to do
- self.__board[i].append(character)
+ self._board[i].extend([None] * int(character))
+ else: # If invalid character - not specified what should happen
+ self._board[i].append(character)
- def __validate_kings_neighbours(self):
- """Validate that both kings are not in 1x1 proximity of each other. Otherwise - raise ChessException."""
- black_king_coords = -2, -2
- white_king_coords = -2, -2
-
- for i, row in enumerate(self.__board):
+ def _validate_kings_neighbours(self):
+ """Validate that both kings are not in close proximity of each other. Otherwise - raise ChessException."""
+ for i, row in enumerate(self._board):
for j, col_value in enumerate(row):
if col_value == 'k':
black_king_coords = i, j
elif col_value == 'K':
white_king_coords = i, j
# If the black king is a neighbour to the white king so is the white one to the black one.
- # The case of having more than 2 kings is already handled by __validate_kings_count so we don't need more checks.
- if white_king_coords[0] - 1 <= black_king_coords[0] <= white_king_coords[0] + 1 and \
- white_king_coords[1] - 1 <= black_king_coords[1] <= white_king_coords[1] + 1:
+ # The case of having more or less than 2 kings is already handled by __validate_kings_count so we don't need more checks.
+ if abs(white_king_coords[0] - black_king_coords[0]) <= 1 and abs(white_king_coords[1] - black_king_coords[1]) <= 1:
raise ChessException('kings')
- def __validate_kings_count(self):
+ def _validate_kings_count(self):
"""Validate that each side has exactly one king piece. Otherwise - raise ChessException."""
- if len(re.findall('k', self.FEN)) != 1 or len(re.findall('K', self.FEN)) != 1:
+ if self.fen.count('k') != 1 or self.fen.count('K') != 1:
raise ChessException('kings')
- # Assuming that pawn always gets promoted to other piece once it's on the opposite side's first row
- def __validate_pawns_positions(self):
- """Validate that there are no pawn pieces on row 1 and 8 of the chess board. Otherwise - raise ChessException."""
- rows = self.FEN.split('/')
- if re.search('[pP]', rows[0]) or re.search('[pP]', rows[-1]):
+ def _validate_pawns_positions(self):
+ """Validate that there are no pawn pieces on the first and last row. Otherwise - raise ChessException."""
+ rows = self.fen.split('/')
+ if 'p' in rows[0].lower() or 'p' in rows[-1].lower():
raise ChessException('pawns')
def get_white_score(self):
"""Return a ChessScore object representing the total score of all white pieces."""
- return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.FEN)))
+ return ChessScore(list(filter(lambda c: c.isupper() and c.lower() in POINTS_PER_PIECE.keys(), self.fen)))
def get_black_score(self):
"""Return a ChessScore object representing the total score of all black pieces."""
- return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.FEN)))
+ return ChessScore(list(filter(lambda c: c.islower() and c in POINTS_PER_PIECE.keys(), self.fen)))
def white_is_winning(self):
"""Check if the total score of the white pieces is greater than the total score of the black pieces."""
return self.get_white_score() > self.get_black_score()
def black_is_winning(self):
"""Check if the total score of the white pieces is less than the total score of the black pieces."""
return self.get_white_score() < self.get_black_score()
def is_equal(self):
"""Check if the total score of the white pieces is equal to the total score of the black pieces."""
return self.get_white_score() == self.get_black_score()
def __str__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
- return self.FEN
+ return self.fen
def __repr__(self):
"""Return the object representation in string format: Chess board in Forsyth-Edwards Notation."""
- return self.FEN
+ return self.fen
def __len__(self):
"""Return the the total number of pieces in this ChessPosition."""
length = 0
for piece in POINTS_PER_PIECE.keys():
- length += self.FEN.count(piece)
- length += self.FEN.count(piece.upper())
+ length += self.fen.count(piece)
+ length += self.fen.count(piece.upper())
return length
def __getitem__(self, coords):
- """Allow indexation of the object by supplying board coordinates in Algebraic notation (ex. A1) as string argument."""
- return self.__board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())] \
- if len(coords) == 2 and coords[0].upper() in BOARD_COLS and coords[1].isdigit() and \
- int(coords[1]) in range(1, len(BOARD_COLS) + 1) else None
+ """Allow indexation of the object by supplying board coordinates in Algebraic notation (e.g. 'A1') as string argument."""
+ if len(coords) != 2:
+ return
+ if coords[0].upper() in BOARD_COLS and coords[1].isdigit() and int(coords[1]) in range(1, len(BOARD_COLS) + 1):
+ return self._board[len(BOARD_COLS) - int(coords[1])][BOARD_COLS.index(coords[0].upper())]
+ else:
+ return
+
class ChessScore:
"""Class representing the total score of all supplied chess pieces."""
- # Не ми стана ясно дали (на обект от този клас) трябва да подавам списък като аргумент или множество аргументи.
- # В описанието пише, че се подава list от str,
- # а в примера под него пише, че при int(ChessScore('r', 'b')) връща 8, като очевидно са подадени 2 аргумента
def __init__(self, pieces):
"""Initialize"""
self._pieces = [piece.lower() for piece in pieces]
def __int__(self):
"""Specify behaviour when object is called with the built-in 'int()' function."""
- result = 0
+ score = 0
for piece, points in POINTS_PER_PIECE.items():
- result += self._pieces.count(piece) * points
- return result
+ score += self._pieces.count(piece) * points
+ return score
def __lt__(self, other):
"""Define functionality of '<' (less than) operator."""
return int(self) < int(other)
def __le__(self, other):
"""Define functionality of '<=' (less than or equal to) operator."""
return int(self) <= int(other)
def __eq__(self, other):
"""Define functionality of '==' (equality) operator."""
return int(self) == int(other)
def __ne__(self, other):
"""Define functionality of '!=' (not equal to) operator."""
return int(self) != int(other)
def __gt__(self, other):
"""Define functionality of '>' (greater than) operator."""
return int(self) > int(other)
def __ge__(self, other):
"""Define functionality of '>=' (greater than or equal to) operator."""
return int(self) >= int(other)
def __add__(self, other):
"""Define functionality of '+' operator between ChessScore object and other object."""
return int(self) + int(other)
def __sub__(self, other):
"""Define functionality of '-' operator between ChessScore object and other object."""
return int(self) - int(other)
- # Може би ненужни?
+ # Potentially unnecessary
def __str__(self):
"""Return the object representation in string format."""
return str(int(self))
def __repr__(self):
"""Return the object representation in string format."""
return str(int(self))