Решение на Шахматни фенове от Боян Богданов

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

Към профила на Боян Богданов

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 14 успешни тест(а)
  • 3 неуспешни тест(а)

Код

piece_values = {"R": 5, "N": 3, "B": 3, "Q": 9, "K": 4, "P": 1}
white_pieces = set(piece_values.keys())
black_pieces = set(map(str.lower, piece_values))
board_size = 8
capital_a_ascii_code = 65
class ChessException(Exception):
pass
# FEN format: 8 strings separated by "/". One for each row
class ChessPosition:
def __init__(self, fen: str):
self.fen = fen
self.board = self._generate_board()
self._validate_board()
self.white_score = self._get_score_for_board_and_pieces(white_pieces)
self.black_score = self._get_score_for_board_and_pieces(black_pieces)
def __getitem__(self, key: str):
col, row = key
col = ord(col.upper()) - capital_a_ascii_code
row = board_size - int(row)
piece = self.board[row][col]
return piece if piece != '-' else None
def __len__(self):
count = 0
for row in self.board:
for cell in row:
if cell in piece_values:
count += 1
return count
def __str__(self):
return self.fen
def _generate_board(self):
rows_content = self.fen.split('/')
board = []
for i, row in enumerate(rows_content):
board.append([])
for piece in row:
if piece.isnumeric():
for _ in range(int(piece)):
board[i].append('-')
else:
board[i].append(piece)
return board
def _validate_board(self):
white_kings = 0
black_kings = 0
for i in range(board_size):

По-добре изнеси валидациите в отделни методи. Става претрупано. Всеки метод трябва да прави възможно най-малко, за да може лесно да се преправя и лесно да се тества.

for j in range(board_size):
piece = self.board[i][j]
if piece.upper() == 'K':
if piece == 'K':
white_kings += 1
else:
black_kings += 1
if self._is_king_adjacent_to_other_king(i, j):
raise ChessException("kings")
elif piece == 'P' and (i == 0 or i == 7):
raise ChessException("pawns")
if white_kings != 1 or black_kings != 1:
raise ChessException("kings")
def _is_king_adjacent_to_other_king(self, king_row, king_col):
for i in range(king_row - 1, king_row + 2):
for j in range(king_col - 1, king_col + 2):
# Don't scan outside of the board boundaries
if i < 0 or i >= board_size or j < 0 or j >= board_size:
continue
# Don't compare the king to itself
if king_row == i and king_col == j:
continue
if self.board[i][j] == 'K':
return True
return False
def _get_score_for_board_and_pieces(self, pieces):
pieces_list = []
for row in self.board:
for piece in row:
if piece in pieces:
pieces_list.append(piece)
return ChessScore(pieces_list)
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.get_white_score() > self.get_black_score()
def black_is_winning(self):
return self.get_black_score() > self.get_white_score()
def is_equal(self):
return self.get_white_score() == self.get_black_score()
class ChessScore:
def __init__(self, pieces):
self.count = 0
for piece in pieces:
self.count += piece_values[piece.upper()]
def __int__(self):
return self.count
def __str__(self):
return str(self.count)
# Comparison operators
def __lt__(self, other):
return self.count < other.count
def __le__(self, other):
return self.count <= other.count
def __eq__(self, other):
return self.count == other.count
def __ne__(self, other):
return self.count != other.count
def __gt__(self, other):
return self.count > other.count
def __ge__(self, other):
return self.count >= other.count
# Arithmetic operators
def __add__(self, other):
return self.count + other.count
def __sub__(self, other):
return self.count - other.count

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

........FE.F.....
======================================================================
ERROR: test_pawns_position (test.TestChessPosition)
Test for incorrect pawns.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221115154139/lib/language/python/runner.py", line 67, in thread
    raise result
Exception: No exception raised on: p7/8/k7/8/7K/8/8/8

======================================================================
FAIL: test_len (test.TestChessPosition)
Test number of pieces for a position.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221115154139/lib/language/python/runner.py", line 67, in thread
    raise result
AssertionError: 4 != 7

======================================================================
FAIL: test_validation_conflict (test.TestChessPosition)
Test for correct Exception on multiple validation fails.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221115154139/lib/language/python/runner.py", line 67, in thread
    raise result
AssertionError: 'pawns' != 'kings'
- pawns
+ kings


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

FAILED (failures=2, errors=1)

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

Боян обнови решението на 23.11.2022 23:18 (преди над 1 година)

+piece_values = {"R": 5, "N": 3, "B": 3, "Q": 9, "K": 4, "P": 1}
+white_pieces = set(piece_values.keys())
+black_pieces = set(map(lambda p: p.lower(), piece_values))
+
+board_size = 8
+capital_a_ascii_code = 65
+
+
+class ChessException(Exception):
+ pass
+
+
+# FEN format: 8 strings separated by "/". One for each row
+class ChessPosition:
+ def __init__(self, fen: str):
+ self.fen = fen
+ self.board = []
+ rows_content = fen.split('/')
+
+ for i, row in enumerate(rows_content):
+ self.board.append([])
+ for piece in row:
+ if piece.isnumeric():
+ for _ in range(int(piece)):
+ self.board[i].append('-')
+ else:
+ self.board[i].append(piece)
+
+ white_kings = 0
+ black_kings = 0
+
+ for i in range(board_size):

По-добре изнеси валидациите в отделни методи. Става претрупано. Всеки метод трябва да прави възможно най-малко, за да може лесно да се преправя и лесно да се тества.

+ for j in range(board_size):
+ piece = self.board[i][j]
+ if piece.upper() == 'K':
+ if piece == 'K':
+ white_kings += 1
+ else:
+ black_kings += 1
+ if self._is_king_adjacent_to_other_king_(i, j):
+ raise ChessException("kings")
+ elif piece == 'P' and (i == 0 or i == 7):
+ raise ChessException("pawns")
+
+ if white_kings != 1 or black_kings != 1:
+ raise ChessException("kings")
+
+ def __getitem__(self, key: str):
+ [col, row] = list(key)

Тук искаш да ънпакнеш. Не се слагат скоби в лявата част. Заблуждаваш, че правиш list, а реално не правиш list. Освен това не е нужно да кастваш дясната част към list.
col, row = key

+ col = ord(col.upper()) - capital_a_ascii_code
+ row = board_size - int(row)
+ return self.board[row][col]
+
+ def __len__(self):
+ count = 0
+ for row in self.board:
+ for cell in row:
+ if cell in piece_values:
+ count += 1
+ return count
+
+ def __str__(self):
+ return self.fen
+
+ def _is_king_adjacent_to_other_king_(self, king_row, king_col):
+ for i in range(king_row - 1, king_row + 2):
+ for j in range(king_col - 1, king_col + 2):
+ if (king_row == i and king_col == j) or i < 0 or i >= board_size or j < 0 or j >= board_size:
+ continue
+ if self.board[i][j] == 'K':
+ return True
+ return False
+
+ def _get_score_for_board_and_pieces_(self, pieces):

Добре е това да се изпълни веднъж - при инициализиране, а не при всяко извикване на метод, който има нужда от резултат. Иначе просто хабиш ресурси.

+ pieces_list = []
+ for row in self.board:
+ for piece in row:
+ if piece in pieces:
+ pieces_list.append(piece)
+ return ChessScore(pieces_list)
+
+ def get_white_score(self):
+ return self._get_score_for_board_and_pieces_(white_pieces)
+
+ def get_black_score(self):
+ return self._get_score_for_board_and_pieces_(black_pieces)
+
+ def white_is_winning(self):
+ return self.get_white_score() > self.get_black_score()
+
+ def black_is_winning(self):
+ return self.get_black_score() > self.get_white_score()
+
+ def is_equal(self):
+ return self.get_white_score() == self.get_black_score()
+
+
+class ChessScore:
+ def __init__(self, pieces):
+ self.count = 0
+ for piece in pieces:
+ self.count += piece_values[piece.upper()]
+
+ def __int__(self):
+ return self.count
+
+ def __str__(self):
+ return str(self.count)
+
+ # Comparison operators
+ def __lt__(self, other):
+ return self.count < other.count
+
+ def __le__(self, other):
+ return self.count <= other.count
+
+ def __eq__(self, other):
+ return self.count == other.count
+
+ def __ne__(self, other):
+ return self.count != other.count
+
+ def __gt__(self, other):
+ return self.count > other.count
+
+ def __ge__(self, other):
+ return self.count >= other.count
+
+ # Arithmetic operators
+ def __add__(self, other):
+ return self.count + other.count
+
+ def __sub__(self, other):
+ return self.count - other.count
+

Съветвам те да изтестваш кода си. Ако понапишеш тестове, ще хванеш разни проблеми. Каквото счетох за уместно, коментирах, но няма да е честно спрямо сотаналите, ако директно ти посоча проблемите.

Боян обнови решението на 24.11.2022 19:12 (преди над 1 година)

piece_values = {"R": 5, "N": 3, "B": 3, "Q": 9, "K": 4, "P": 1}
white_pieces = set(piece_values.keys())
-black_pieces = set(map(lambda p: p.lower(), piece_values))
+black_pieces = set(map(str.lower, piece_values))
+print(black_pieces)
board_size = 8
capital_a_ascii_code = 65
class ChessException(Exception):
pass
# FEN format: 8 strings separated by "/". One for each row
class ChessPosition:
def __init__(self, fen: str):
self.fen = fen
- self.board = []
- rows_content = fen.split('/')
+ self.board = self._generate_board()
+ self._validate_board()
+ self.white_score = self._get_score_for_board_and_pieces(white_pieces)
+ self.black_score = self._get_score_for_board_and_pieces(black_pieces)
+ def __getitem__(self, key: str):
+ col, row = key
+ col = ord(col.upper()) - capital_a_ascii_code
+ row = board_size - int(row)
+ piece = self.board[row][col]
+ return piece if piece != '-' else None
+
+ def __len__(self):
+ count = 0
+ for row in self.board:
+ for cell in row:
+ if cell in piece_values:
+ count += 1
+ return count
+
+ def __str__(self):
+ return self.fen
+
+ def _generate_board(self):
+ rows_content = self.fen.split('/')
+ board = []
for i, row in enumerate(rows_content):
- self.board.append([])
+ board.append([])
for piece in row:
if piece.isnumeric():
for _ in range(int(piece)):
- self.board[i].append('-')
+ board[i].append('-')
else:
- self.board[i].append(piece)
+ board[i].append(piece)
+ return board
+ def _validate_board(self):
white_kings = 0
black_kings = 0
for i in range(board_size):
for j in range(board_size):
piece = self.board[i][j]
if piece.upper() == 'K':
if piece == 'K':
white_kings += 1
else:
black_kings += 1
- if self._is_king_adjacent_to_other_king_(i, j):
+ if self._is_king_adjacent_to_other_king(i, j):
raise ChessException("kings")
elif piece == 'P' and (i == 0 or i == 7):
raise ChessException("pawns")
if white_kings != 1 or black_kings != 1:
raise ChessException("kings")
- def __getitem__(self, key: str):
- [col, row] = list(key)
- col = ord(col.upper()) - capital_a_ascii_code
- row = board_size - int(row)
- return self.board[row][col]
-
- def __len__(self):
- count = 0
- for row in self.board:
- for cell in row:
- if cell in piece_values:
- count += 1
- return count
-
- def __str__(self):
- return self.fen
-
- def _is_king_adjacent_to_other_king_(self, king_row, king_col):
+ def _is_king_adjacent_to_other_king(self, king_row, king_col):
for i in range(king_row - 1, king_row + 2):
for j in range(king_col - 1, king_col + 2):
- if (king_row == i and king_col == j) or i < 0 or i >= board_size or j < 0 or j >= board_size:
+ # Don't scan outside of the board boundaries
+ if i < 0 or i >= board_size or j < 0 or j >= board_size:
continue
+ # Don't compare the king to itself
+ if king_row == i and king_col == j:
+ continue
+
if self.board[i][j] == 'K':
return True
return False
- def _get_score_for_board_and_pieces_(self, pieces):
+ def _get_score_for_board_and_pieces(self, pieces):
pieces_list = []
for row in self.board:
for piece in row:
if piece in pieces:
pieces_list.append(piece)
return ChessScore(pieces_list)
def get_white_score(self):
- return self._get_score_for_board_and_pieces_(white_pieces)
+ return self.white_score
def get_black_score(self):
- return self._get_score_for_board_and_pieces_(black_pieces)
+ return self.black_score
def white_is_winning(self):
return self.get_white_score() > self.get_black_score()
def black_is_winning(self):
return self.get_black_score() > self.get_white_score()
def is_equal(self):
return self.get_white_score() == self.get_black_score()
class ChessScore:
def __init__(self, pieces):
self.count = 0
for piece in pieces:
self.count += piece_values[piece.upper()]
def __int__(self):
return self.count
def __str__(self):
return str(self.count)
# Comparison operators
def __lt__(self, other):
return self.count < other.count
def __le__(self, other):
return self.count <= other.count
def __eq__(self, other):
return self.count == other.count
def __ne__(self, other):
return self.count != other.count
def __gt__(self, other):
return self.count > other.count
def __ge__(self, other):
return self.count >= other.count
# Arithmetic operators
def __add__(self, other):
return self.count + other.count
def __sub__(self, other):
return self.count - other.count

Боян обнови решението на 24.11.2022 19:13 (преди над 1 година)

piece_values = {"R": 5, "N": 3, "B": 3, "Q": 9, "K": 4, "P": 1}
white_pieces = set(piece_values.keys())
black_pieces = set(map(str.lower, piece_values))
-print(black_pieces)
board_size = 8
capital_a_ascii_code = 65
class ChessException(Exception):
pass
# FEN format: 8 strings separated by "/". One for each row
class ChessPosition:
def __init__(self, fen: str):
self.fen = fen
self.board = self._generate_board()
self._validate_board()
self.white_score = self._get_score_for_board_and_pieces(white_pieces)
self.black_score = self._get_score_for_board_and_pieces(black_pieces)
def __getitem__(self, key: str):
col, row = key
col = ord(col.upper()) - capital_a_ascii_code
row = board_size - int(row)
piece = self.board[row][col]
return piece if piece != '-' else None
def __len__(self):
count = 0
for row in self.board:
for cell in row:
if cell in piece_values:
count += 1
return count
def __str__(self):
return self.fen
def _generate_board(self):
rows_content = self.fen.split('/')
board = []
for i, row in enumerate(rows_content):
board.append([])
for piece in row:
if piece.isnumeric():
for _ in range(int(piece)):
board[i].append('-')
else:
board[i].append(piece)
return board
def _validate_board(self):
white_kings = 0
black_kings = 0
for i in range(board_size):
for j in range(board_size):
piece = self.board[i][j]
if piece.upper() == 'K':
if piece == 'K':
white_kings += 1
else:
black_kings += 1
if self._is_king_adjacent_to_other_king(i, j):
raise ChessException("kings")
elif piece == 'P' and (i == 0 or i == 7):
raise ChessException("pawns")
if white_kings != 1 or black_kings != 1:
raise ChessException("kings")
def _is_king_adjacent_to_other_king(self, king_row, king_col):
for i in range(king_row - 1, king_row + 2):
for j in range(king_col - 1, king_col + 2):
# Don't scan outside of the board boundaries
if i < 0 or i >= board_size or j < 0 or j >= board_size:
continue
# Don't compare the king to itself
if king_row == i and king_col == j:
continue
if self.board[i][j] == 'K':
return True
return False
def _get_score_for_board_and_pieces(self, pieces):
pieces_list = []
for row in self.board:
for piece in row:
if piece in pieces:
pieces_list.append(piece)
return ChessScore(pieces_list)
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.get_white_score() > self.get_black_score()
def black_is_winning(self):
return self.get_black_score() > self.get_white_score()
def is_equal(self):
return self.get_white_score() == self.get_black_score()
class ChessScore:
def __init__(self, pieces):
self.count = 0
for piece in pieces:
self.count += piece_values[piece.upper()]
def __int__(self):
return self.count
def __str__(self):
return str(self.count)
# Comparison operators
def __lt__(self, other):
return self.count < other.count
def __le__(self, other):
return self.count <= other.count
def __eq__(self, other):
return self.count == other.count
def __ne__(self, other):
return self.count != other.count
def __gt__(self, other):
return self.count > other.count
def __ge__(self, other):
return self.count >= other.count
# Arithmetic operators
def __add__(self, other):
return self.count + other.count
def __sub__(self, other):
return self.count - other.count