Решение на Шахматни фенове от Йордан Глигоров

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

Към профила на Йордан Глигоров

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 15 успешни тест(а)
  • 2 неуспешни тест(а)

Код

class ChessException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
BLACK_FIGURES = ['r', 'n', 'b', 'k', 'q', 'p']
WHITE_FIGURES = ['R', 'N', 'B', 'K', 'Q', 'P']
class ChessPosition:
def __init__(self, fen):
self._modified_fen = self.modify_fen(fen)
self.ROW_SIZE = 8
self.validate_fen(fen)
self._fen = fen
self.__set_up_white_score()
self.__set_up_black_score()
def __set_up_white_score(self):
self._white_figures = list(filter(lambda x: x in WHITE_FIGURES, self._fen))
self._white_chess_score = ChessScore(self._white_figures)
def __set_up_black_score(self):
self._black_figures = list(filter(lambda x: x in BLACK_FIGURES, self._fen))
self._black_chess_score = ChessScore(self._black_figures)
def validate_fen(self, fen: str):
bk_indices = [i for i, x in enumerate(fen) if x == "k"]
wk_indicies = [i for i, x in enumerate(fen) if x == "K"]
#check whether there is only one black and one white king
if len(bk_indices) != 1:
raise ChessException("kings")
if len(wk_indicies) != 1:
raise ChessException("kings")
bk_index = bk_indices[0]
#check whether two Kings are adjacent
neighbours = [bk_index - 1, bk_index + 1,
bk_index - self.ROW_SIZE, bk_index + self.ROW_SIZE,
bk_index - 1 - self.ROW_SIZE, bk_index - 1 + self.ROW_SIZE,
bk_index + 1 - self.ROW_SIZE, bk_index + 1 + self.ROW_SIZE]
for neighbour in neighbours:
try:
if neighbour >= 0 and self._modified_fen[neighbour] == 'K':
raise ChessException("kings")
except IndexError:
continue
#check for pawns
rows = fen.split('/')
if 'p' in rows[0] or 'p' in rows[-1]:
raise ChessException("pawns")
if 'P' in rows[0] or 'P' in rows[-1]:
raise ChessException("pawns")
def modify_fen(self, fenstr):
"""Modify the FEN by changing the numbers into -, exaple: 3P4 -> ---P----."""
for el in fenstr:
if el.isdigit():
i = fenstr.index(el)
before = fenstr[0:i]
after = fenstr[i + 1:]
middle = int(el) * '-'
fenstr = before + middle + after
return fenstr
def get_white_score(self):
return self._white_chess_score
def get_black_score(self):
return self._black_chess_score
def white_is_winning(self):
return self._white_chess_score > self._black_chess_score
def black_is_winning(self):
return self._black_chess_score > self._white_chess_score
def is_equal(self):
return self._black_chess_score == self._white_chess_score
def __str__(self):
return self._fen
def __len__(self):
return len(list(filter(lambda x: x in WHITE_FIGURES or x in BLACK_FIGURES, self._fen)))
def __getitem__(self, index):
#A, B, C, ... -> horizontal
#8, 7, 6, ... -> vertical
board_values = { 8: 0, 7: 1, 6: 2, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}

Бих предпочел да подготвя речник, който съдържа fen в готов формат, така че тук просто да попитам какво има на конкретните координати, без да правя допълнителни проверки и модификации на координатите. Тази дефиниция с мапинга на индексите ми седи изкуствено. Обхождайки списъка отзад напред би постигнал същото, но без експлицитно дефиниране на съответствията.

horizontal = index[0].upper()
vertical = int(index[1])
horizontal = ord(horizontal) - ord('A')
vertical = board_values[vertical]
board = self._modified_fen.split('/')
try:
return board[vertical][horizontal] if board[vertical][horizontal] != '-' else None
except IndexError:
return None
class ChessScore:
def __init__(self, figures):
self._figures = figures
self.FIGURE_VALUES = {'r': 5, 'n': 3, 'b': 3, 'k': 4, 'q': 9, 'p': 1,
'R': 5, 'N': 3, 'B': 3, 'K': 4, 'Q': 9, 'P': 1}
self._validate_figures()
def _validate_figures(self):
for figure in self._figures:
if figure not in self.FIGURE_VALUES.keys():
raise ChessException(f'{figure} is an invalid figure')
def __str__(self):
return str(int(self))
def __int__(self):
return sum(map(lambda x: self.FIGURE_VALUES[x], self._figures))
def __gt__(self, other):
return int(self) > int(other)
def __lt__(self, other):
return int(self) < int(other)
def __eq__(self, other):
return int(self) == int(other)
def __le__(self, other):
return int(self) <= int(other)
def __ge__(self, other):
return int(self) >= int(other)
def __ne__(self, other):
return int(self) != int(other)
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)

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

.E.........F.....
======================================================================
ERROR: test_against_touching_kings (test.TestChessPosition)
Test for kings next to each other.
----------------------------------------------------------------------
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: 8/8/8/3kK3/8/8/8/8

======================================================================
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.171s

FAILED (failures=1, errors=1)

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

Йордан обнови решението на 25.11.2022 14:39 (преди над 1 година)

+FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
+
+class ChessException(Exception):
+ """Chess exception"""
+ pass
+
+# r - black R-white
+# "R/r" - Rook (топ)
+# - "N/n" - Knight (кон) /използва се "N", а не "K", защото се припокриват с царя/
+# - "B/b" - Bishop (офицер)
+# - "Q/q" - Queen (дама)
+# - "K/k" - King (цар)
+# - "P/p" - Pawn (пешка)
+
+BLACK_FIGURES = ['r', 'n', 'b', 'k', 'q', 'p']
+WHITE_FIGURES = ['R', 'N', 'B', 'K', 'Q', 'P']
+
+class ChessPosition:
+ def __init__(self, fen):
+ self.__modified_fens = self.modify_fens(fen)
+ self.validateFen(fen)
+ self.__fen = fen
+
+ def validateFen(self, fen: str) -> bool:
+ #check whether two Kings are adjacent
+ ROW_SIZE = 8
+ bk_indices = [i for i, x in enumerate(fen) if x == "k"]
+ wk_indixies = [i for i, x in enumerate(fen) if x == "K"]
+
+ if len(bk_indices) != 1:
+ raise ChessException
+ if len(wk_indixies) != 1:
+ raise ChessException
+
+ bk_index = bk_indices[0]
+
+ neighbours = [bk_index - 1, bk_index + 1,
+ bk_index - ROW_SIZE, bk_index + ROW_SIZE,
+ bk_index - 1 - ROW_SIZE, bk_index - 1 + ROW_SIZE,
+ bk_index + 1 - ROW_SIZE, bk_index + 1 + ROW_SIZE]
+ #modify the fen for 3P4 -> ---P----
+ for neighbour in neighbours:
+ try:
+ if neighbour >= 0 and self.__modified_fens[neighbour] == 'K':
+ raise ChessException
+ except IndexError:
+ continue
+
+ #check for pawns
+ rows = fen.split('/')
+ if 'p' in rows[0] or 'p' in rows[-1]:
+ raise ChessException
+
+ if 'P' in rows[0] or 'P' in rows[-1]:
+ raise ChessException
+
+ def modify_fens(self, fenstr):
+ for el in fenstr:
+ if '1' <= el <= '8':
+ i = fenstr.index(el)
+ before = fenstr[0:i]
+ after = fenstr[i + 1:]
+ middle = int(el) * '-'
+ fenstr = before + middle + after
+ return fenstr
+
+ def get_white_score(self):
+ white_figures = list(filter(lambda x : x in WHITE_FIGURES, self.__fen))
+ return ChessScore(white_figures)
+
+ def get_black_score(self):
+ black_figures = list(filter(lambda x : x in BLACK_FIGURES, self.__fen))
+ return ChessScore(black_figures)
+
+ def white_is_winning(self):
+ white_chess_score = self.get_white_score()
+ black_chess_score = self.get_black_score()
+ return white_chess_score > black_chess_score
+
+ def black_is_winning(self):
+ white_chess_score = self.get_white_score()
+ black_chess_score = self.get_black_score()
+ return black_chess_score > white_chess_score
+
+ def is_equal(self):
+ white_chess_score = self.get_white_score()
+ black_chess_score = self.get_black_score()
+ return black_chess_score == white_chess_score
+
+ def __str__(self):
+ return self.__fen
+
+ def __len__(self):
+ return len(list(filter(lambda x : x in WHITE_FIGURES or x in BLACK_FIGURES, self.__fen)))
+
+ def __getitem__(self, index):
+ #A, B, C, ... -> horizontal
+ #8, 7, 6, ... -> vertical
+ board_values = { 8: 0, 7: 1, 6: 2, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}
+ horizontal = index[0]
+ vertical = int(index[1])
+
+ horizontal = ord(horizontal) - ord('A')
+ vertical = board_values[vertical]
+
+ board = self.__modified_fens.split('/')
+ return board[vertical][horizontal]
+
+
+class ChessScore:
+ def __init__(self, figures):
+ self._figures = figures
+ self.FIGURE_VALUES = {'r': 5, 'n': 3, 'b': 3, 'k': 4, 'q': 9, 'p': 1,
+ 'R': 5, 'N': 3, 'B': 3, 'K': 4, 'Q': 9, 'P': 1}
+ self.validate_figures()
+
+ def validate_figures(self):
+ for figure in self._figures:
+ if figure not in self.FIGURE_VALUES.keys():
+ raise ChessException
+
+ def __str__(self):
+ return str(sum(map(lambda x : self.FIGURE_VALUES[x], self._figures)))
+
+ def __int__(self):
+ return int(self.__str__())
+
+ def __gt__(self, other):
+ return int(self.__str__()) > int(other.__str__())
+
+ def __lt__(self, other):
+ return int(self.__str__()) < int(other.__str__())
+
+ def __eq__(self, other):
+ return int(self.__str__()) == int(other.__str__())
+
+ def __le__(self, other):
+ return int(self.__str__()) <= int(other.__str__())
+
+ def __ge__(self, other):
+ return int(self.__str__()) >= int(other.__str__())
+
+ def __ne__(self, other):
+ return int(self.__str__()) != int(other.__str__())
+
+ def __add__(self, other):
+ return int(self.__str__()) + int(other.__str__())
+
+ def __sub__(self, other):
+ return int(self.__str__()) - int(other.__str__())

Йордан обнови решението на 26.11.2022 22:21 (преди над 1 година)

-FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
-
class ChessException(Exception):
- """Chess exception"""
- pass
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return(repr(self.value))
-# r - black R-white
-# "R/r" - Rook (топ)
-# - "N/n" - Knight (кон) /използва се "N", а не "K", защото се припокриват с царя/
-# - "B/b" - Bishop (офицер)
-# - "Q/q" - Queen (дама)
-# - "K/k" - King (цар)
-# - "P/p" - Pawn (пешка)
-
BLACK_FIGURES = ['r', 'n', 'b', 'k', 'q', 'p']
WHITE_FIGURES = ['R', 'N', 'B', 'K', 'Q', 'P']
class ChessPosition:
def __init__(self, fen):
self.__modified_fens = self.modify_fens(fen)
self.validateFen(fen)
self.__fen = fen
def validateFen(self, fen: str) -> bool:
- #check whether two Kings are adjacent
ROW_SIZE = 8

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

bk_indices = [i for i, x in enumerate(fen) if x == "k"]
wk_indixies = [i for i, x in enumerate(fen) if x == "K"]
+ #check whether there is only one black and one white king
if len(bk_indices) != 1:
- raise ChessException
+ raise ChessException("kings")
if len(wk_indixies) != 1:
- raise ChessException
+ raise ChessException("kings")
bk_index = bk_indices[0]
+ #check whether two Kings are adjacent
neighbours = [bk_index - 1, bk_index + 1,
bk_index - ROW_SIZE, bk_index + ROW_SIZE,
bk_index - 1 - ROW_SIZE, bk_index - 1 + ROW_SIZE,
bk_index + 1 - ROW_SIZE, bk_index + 1 + ROW_SIZE]
- #modify the fen for 3P4 -> ---P----
+
for neighbour in neighbours:
try:
if neighbour >= 0 and self.__modified_fens[neighbour] == 'K':
- raise ChessException
+ raise ChessException("kings")
except IndexError:
continue
#check for pawns
rows = fen.split('/')
if 'p' in rows[0] or 'p' in rows[-1]:
- raise ChessException
+ raise ChessException("pawns")
if 'P' in rows[0] or 'P' in rows[-1]:
- raise ChessException
+ raise ChessException("pawns")
def modify_fens(self, fenstr):
+ """modifies the FEN by changing the numbers into -, exaple: 3P4 -> ---P----"""

Докстринговете трябва да започват с главна буква, да завършват с точка (т.е. да са изречение). Освен това трябва да са в запоевдна форма - "modify", а не "modifies".

for el in fenstr:
i = fenstr.index(el)
before = fenstr[0:i]
after = fenstr[i + 1:]
middle = int(el) * '-'
fenstr = before + middle + after
return fenstr
def get_white_score(self):
white_figures = list(filter(lambda x : x in WHITE_FIGURES, self.__fen))
return ChessScore(white_figures)
def get_black_score(self):
black_figures = list(filter(lambda x : x in BLACK_FIGURES, self.__fen))
return ChessScore(black_figures)
def white_is_winning(self):
white_chess_score = self.get_white_score()
black_chess_score = self.get_black_score()
return white_chess_score > black_chess_score
def black_is_winning(self):
white_chess_score = self.get_white_score()
black_chess_score = self.get_black_score()
return black_chess_score > white_chess_score
def is_equal(self):
white_chess_score = self.get_white_score()
black_chess_score = self.get_black_score()
return black_chess_score == white_chess_score
def __str__(self):
return self.__fen
def __len__(self):
return len(list(filter(lambda x : x in WHITE_FIGURES or x in BLACK_FIGURES, self.__fen)))
def __getitem__(self, index):
#A, B, C, ... -> horizontal
#8, 7, 6, ... -> vertical
board_values = { 8: 0, 7: 1, 6: 2, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}

Бих предпочел да подготвя речник, който съдържа fen в готов формат, така че тук просто да попитам какво има на конкретните координати, без да правя допълнителни проверки и модификации на координатите. Тази дефиниция с мапинга на индексите ми седи изкуствено. Обхождайки списъка отзад напред би постигнал същото, но без експлицитно дефиниране на съответствията.

horizontal = index[0]
vertical = int(index[1])
horizontal = ord(horizontal) - ord('A')
vertical = board_values[vertical]
board = self.__modified_fens.split('/')
return board[vertical][horizontal]
class ChessScore:
def __init__(self, figures):
self._figures = figures
self.FIGURE_VALUES = {'r': 5, 'n': 3, 'b': 3, 'k': 4, 'q': 9, 'p': 1,
'R': 5, 'N': 3, 'B': 3, 'K': 4, 'Q': 9, 'P': 1}
self.validate_figures()
def validate_figures(self):
for figure in self._figures:
if figure not in self.FIGURE_VALUES.keys():
raise ChessException
def __str__(self):
return str(sum(map(lambda x : self.FIGURE_VALUES[x], self._figures)))
def __int__(self):
return int(self.__str__())

По-скоро добави sum функцията от __str__ тук и преправи __str__ да връща str(int(self)). Ще работи по-бързо, защото ще трябва да кастваш към стринг само ако ти трябва като стринг, което е по-рядка операция, имайки предвид естеството на класа.

def __gt__(self, other):
return int(self.__str__()) > int(other.__str__())
def __lt__(self, other):
return int(self.__str__()) < int(other.__str__())
def __eq__(self, other):
return int(self.__str__()) == int(other.__str__())
def __le__(self, other):
return int(self.__str__()) <= int(other.__str__())
def __ge__(self, other):
return int(self.__str__()) >= int(other.__str__())
def __ne__(self, other):
return int(self.__str__()) != int(other.__str__())
def __add__(self, other):
return int(self.__str__()) + int(other.__str__())
def __sub__(self, other):
return int(self.__str__()) - int(other.__str__())

Йордан обнови решението на 28.11.2022 12:07 (преди над 1 година)

class ChessException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
- return(repr(self.value))
+ return self.value
BLACK_FIGURES = ['r', 'n', 'b', 'k', 'q', 'p']
WHITE_FIGURES = ['R', 'N', 'B', 'K', 'Q', 'P']
class ChessPosition:
def __init__(self, fen):
- self.__modified_fens = self.modify_fens(fen)
- self.validateFen(fen)
- self.__fen = fen
+ self._modified_fen = self.modify_fen(fen)
+ self.ROW_SIZE = 8
+ self.validate_fen(fen)
+ self._fen = fen
+ self.__set_up_white_score()
+ self.__set_up_black_score()
- def validateFen(self, fen: str) -> bool:
- ROW_SIZE = 8
+ def __set_up_white_score(self):
+ self._white_figures = list(filter(lambda x: x in WHITE_FIGURES, self._fen))
+ self._white_chess_score = ChessScore(self._white_figures)
+
+ def __set_up_black_score(self):
+ self._black_figures = list(filter(lambda x: x in BLACK_FIGURES, self._fen))
+ self._black_chess_score = ChessScore(self._black_figures)
+
+ def validate_fen(self, fen: str):
bk_indices = [i for i, x in enumerate(fen) if x == "k"]
- wk_indixies = [i for i, x in enumerate(fen) if x == "K"]
+ wk_indicies = [i for i, x in enumerate(fen) if x == "K"]
#check whether there is only one black and one white king
if len(bk_indices) != 1:
raise ChessException("kings")
- if len(wk_indixies) != 1:
+ if len(wk_indicies) != 1:
raise ChessException("kings")
bk_index = bk_indices[0]
#check whether two Kings are adjacent
neighbours = [bk_index - 1, bk_index + 1,
- bk_index - ROW_SIZE, bk_index + ROW_SIZE,
- bk_index - 1 - ROW_SIZE, bk_index - 1 + ROW_SIZE,
- bk_index + 1 - ROW_SIZE, bk_index + 1 + ROW_SIZE]
+ bk_index - self.ROW_SIZE, bk_index + self.ROW_SIZE,
+ bk_index - 1 - self.ROW_SIZE, bk_index - 1 + self.ROW_SIZE,
+ bk_index + 1 - self.ROW_SIZE, bk_index + 1 + self.ROW_SIZE]
for neighbour in neighbours:
try:
- if neighbour >= 0 and self.__modified_fens[neighbour] == 'K':
+ if neighbour >= 0 and self._modified_fen[neighbour] == 'K':
raise ChessException("kings")
except IndexError:
continue
#check for pawns
rows = fen.split('/')
if 'p' in rows[0] or 'p' in rows[-1]:
raise ChessException("pawns")
if 'P' in rows[0] or 'P' in rows[-1]:
raise ChessException("pawns")
- def modify_fens(self, fenstr):
- """modifies the FEN by changing the numbers into -, exaple: 3P4 -> ---P----"""
+ def modify_fen(self, fenstr):
+ """Modify the FEN by changing the numbers into -, exaple: 3P4 -> ---P----."""
for el in fenstr:
if '1' <= el <= '8':
i = fenstr.index(el)
before = fenstr[0:i]
after = fenstr[i + 1:]
middle = int(el) * '-'
fenstr = before + middle + after
return fenstr
def get_white_score(self):
- white_figures = list(filter(lambda x : x in WHITE_FIGURES, self.__fen))
- return ChessScore(white_figures)
+ return self._white_chess_score
def get_black_score(self):
- black_figures = list(filter(lambda x : x in BLACK_FIGURES, self.__fen))
- return ChessScore(black_figures)
+ return self._black_chess_score
def white_is_winning(self):
- white_chess_score = self.get_white_score()
- black_chess_score = self.get_black_score()
- return white_chess_score > black_chess_score
+ return self._white_chess_score > self._black_chess_score
def black_is_winning(self):
- white_chess_score = self.get_white_score()
- black_chess_score = self.get_black_score()
- return black_chess_score > white_chess_score
+ return self._black_chess_score > self._white_chess_score
def is_equal(self):
- white_chess_score = self.get_white_score()
- black_chess_score = self.get_black_score()
- return black_chess_score == white_chess_score
+ return self._black_chess_score == self._white_chess_score
def __str__(self):
- return self.__fen
+ return self._fen
def __len__(self):
- return len(list(filter(lambda x : x in WHITE_FIGURES or x in BLACK_FIGURES, self.__fen)))
+ return len(list(filter(lambda x: x in WHITE_FIGURES or x in BLACK_FIGURES, self._fen)))
def __getitem__(self, index):
#A, B, C, ... -> horizontal
#8, 7, 6, ... -> vertical
board_values = { 8: 0, 7: 1, 6: 2, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}
- horizontal = index[0]
+ horizontal = index[0].upper()
vertical = int(index[1])
horizontal = ord(horizontal) - ord('A')
vertical = board_values[vertical]
- board = self.__modified_fens.split('/')
- return board[vertical][horizontal]
+ board = self._modified_fen.split('/')
+ try:
+ return board[vertical][horizontal] if board[vertical][horizontal] != '-' else None
+ except IndexError:
+ return None
class ChessScore:
def __init__(self, figures):
self._figures = figures
self.FIGURE_VALUES = {'r': 5, 'n': 3, 'b': 3, 'k': 4, 'q': 9, 'p': 1,
'R': 5, 'N': 3, 'B': 3, 'K': 4, 'Q': 9, 'P': 1}
- self.validate_figures()
+ self._validate_figures()
- def validate_figures(self):
+ def _validate_figures(self):
for figure in self._figures:
if figure not in self.FIGURE_VALUES.keys():
- raise ChessException
+ raise ChessException(f'{figure} is an invalid figure')
def __str__(self):
- return str(sum(map(lambda x : self.FIGURE_VALUES[x], self._figures)))
-
+ return str(int(self))
+
def __int__(self):
- return int(self.__str__())
+ return sum(map(lambda x: self.FIGURE_VALUES[x], self._figures))
def __gt__(self, other):
- return int(self.__str__()) > int(other.__str__())
+ return int(self) > int(other)
def __lt__(self, other):
- return int(self.__str__()) < int(other.__str__())
+ return int(self) < int(other)
def __eq__(self, other):
- return int(self.__str__()) == int(other.__str__())
+ return int(self) == int(other)
def __le__(self, other):
- return int(self.__str__()) <= int(other.__str__())
+ return int(self) <= int(other)
def __ge__(self, other):
- return int(self.__str__()) >= int(other.__str__())
+ return int(self) >= int(other)
def __ne__(self, other):
- return int(self.__str__()) != int(other.__str__())
+ return int(self) != int(other)
def __add__(self, other):
- return int(self.__str__()) + int(other.__str__())
+ return int(self) + int(other)
def __sub__(self, other):
- return int(self.__str__()) - int(other.__str__())
+ return int(self) - int(other)

Йордан обнови решението на 28.11.2022 23:36 (преди над 1 година)

class ChessException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
BLACK_FIGURES = ['r', 'n', 'b', 'k', 'q', 'p']
WHITE_FIGURES = ['R', 'N', 'B', 'K', 'Q', 'P']
class ChessPosition:
def __init__(self, fen):
self._modified_fen = self.modify_fen(fen)
self.ROW_SIZE = 8
self.validate_fen(fen)
self._fen = fen
self.__set_up_white_score()
self.__set_up_black_score()
def __set_up_white_score(self):
self._white_figures = list(filter(lambda x: x in WHITE_FIGURES, self._fen))
self._white_chess_score = ChessScore(self._white_figures)
def __set_up_black_score(self):
self._black_figures = list(filter(lambda x: x in BLACK_FIGURES, self._fen))
self._black_chess_score = ChessScore(self._black_figures)
def validate_fen(self, fen: str):
bk_indices = [i for i, x in enumerate(fen) if x == "k"]
wk_indicies = [i for i, x in enumerate(fen) if x == "K"]
#check whether there is only one black and one white king
if len(bk_indices) != 1:
raise ChessException("kings")
if len(wk_indicies) != 1:
raise ChessException("kings")
bk_index = bk_indices[0]
#check whether two Kings are adjacent
neighbours = [bk_index - 1, bk_index + 1,
bk_index - self.ROW_SIZE, bk_index + self.ROW_SIZE,
bk_index - 1 - self.ROW_SIZE, bk_index - 1 + self.ROW_SIZE,
bk_index + 1 - self.ROW_SIZE, bk_index + 1 + self.ROW_SIZE]
for neighbour in neighbours:
try:
if neighbour >= 0 and self._modified_fen[neighbour] == 'K':
raise ChessException("kings")
except IndexError:
continue
#check for pawns
rows = fen.split('/')
if 'p' in rows[0] or 'p' in rows[-1]:
raise ChessException("pawns")
if 'P' in rows[0] or 'P' in rows[-1]:
raise ChessException("pawns")
def modify_fen(self, fenstr):
"""Modify the FEN by changing the numbers into -, exaple: 3P4 -> ---P----."""
for el in fenstr:
- if '1' <= el <= '8':
+ if el.isdigit():
i = fenstr.index(el)
before = fenstr[0:i]
after = fenstr[i + 1:]
middle = int(el) * '-'
fenstr = before + middle + after
return fenstr
def get_white_score(self):
return self._white_chess_score
def get_black_score(self):
return self._black_chess_score
def white_is_winning(self):
return self._white_chess_score > self._black_chess_score
def black_is_winning(self):
return self._black_chess_score > self._white_chess_score
def is_equal(self):
return self._black_chess_score == self._white_chess_score
def __str__(self):
return self._fen
def __len__(self):
return len(list(filter(lambda x: x in WHITE_FIGURES or x in BLACK_FIGURES, self._fen)))
def __getitem__(self, index):
#A, B, C, ... -> horizontal
#8, 7, 6, ... -> vertical
board_values = { 8: 0, 7: 1, 6: 2, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}
horizontal = index[0].upper()
vertical = int(index[1])
horizontal = ord(horizontal) - ord('A')
vertical = board_values[vertical]
board = self._modified_fen.split('/')
try:
return board[vertical][horizontal] if board[vertical][horizontal] != '-' else None
except IndexError:
return None
class ChessScore:
def __init__(self, figures):
self._figures = figures
self.FIGURE_VALUES = {'r': 5, 'n': 3, 'b': 3, 'k': 4, 'q': 9, 'p': 1,
'R': 5, 'N': 3, 'B': 3, 'K': 4, 'Q': 9, 'P': 1}
self._validate_figures()
def _validate_figures(self):
for figure in self._figures:
if figure not in self.FIGURE_VALUES.keys():
raise ChessException(f'{figure} is an invalid figure')
def __str__(self):
return str(int(self))
def __int__(self):
return sum(map(lambda x: self.FIGURE_VALUES[x], self._figures))
def __gt__(self, other):
return int(self) > int(other)
def __lt__(self, other):
return int(self) < int(other)
def __eq__(self, other):
return int(self) == int(other)
def __le__(self, other):
return int(self) <= int(other)
def __ge__(self, other):
return int(self) >= int(other)
def __ne__(self, other):
return int(self) != int(other)
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)