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

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

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

Резултати

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

Код

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 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)):
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)
'''

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

.................
----------------------------------------------------------------------
Ran 17 tests in 0.176s

OK

История (1 версия и 5 коментара)

Александър обнови решението на 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 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)):
+ 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)
+'''