def test_get_path(self, src_label, dst_label, expected_path_labels): src = Location(src_label) dst = Location(dst_label) actual_path = src.get_path(dst) expected_path = [Location(label) for label in expected_path_labels] self.assertIsInstance(actual_path, list) self.assertEqual(actual_path, expected_path)
class NormalMove(Move): def __init__(self, session, src_label, dst_label): super(NormalMove, self).__init__(session) self.src = Location(src_label) self.dst = Location(dst_label) self.piece = session.board[self.src] self._en_passant_attack_dst = None def get_vector(self): return self.src.get_vector(self.dst) def get_path(self): return self.src.get_path(self.dst) def execute(self): self._validate_and_prepare() with critical_part(): self._mutate_board() self._maintain_future_castlings() # non-public helpers: def _validate_and_prepare(self): self._check_src_not_empty() self._check_if_player_owns_src_piece() self._check_src_dst_are_distinct() route = self.piece.get_route(self) self._check_path(route) self._check_dst_field(route) def _mutate_board(self): moved_piece = self._session.board.pop_piece(self.src) assert moved_piece is self.piece self._session.board[self.dst] = moved_piece if self._en_passant_attack_dst: del self._session.board[self._en_passant_attack_dst] def _maintain_future_castlings(self): player = self._session.current_player if self._should_disable_queenside_castlings(): player.queenside_castling_enabled = False if self._should_disable_kingside_castlings(): player.kingside_castling_enabled = False def _check_src_not_empty(self): if self.piece is None: raise UserActionError('Source location does not contain any figure.') def _check_if_player_owns_src_piece(self): if self.piece.is_white != self._session.is_white_turn: raise UserActionError('You tried to move not your piece.') def _check_src_dst_are_distinct(self): if self.get_vector() == (0, 0): raise UserActionError('You tried to move to the same location.') def _check_path(self, route): for loc in route.path: if self._session.board[loc] is not None: raise UserActionError('Other piece on move path.') def _check_dst_field(self, route): dst_piece = self._session.board[self.dst] if route.attack_required: assert isinstance(self.piece, Pawn) if not dst_piece: self._check_en_passant() elif self.piece.is_white == dst_piece.is_white: raise UserActionError('This move has to be an attack.') if route.attack_forbidden: if dst_piece: raise UserActionError('This move can\'t be an attack.') if dst_piece and self.piece.is_white == dst_piece.is_white: raise UserActionError('You tried to attack your\'s piece.') def _check_en_passant(self): if not self._session.last_move: raise UserActionError('Invalid en passant attack.') last_move = self._session.last_move if not isinstance(self.piece, Pawn) or not isinstance(last_move.piece, Pawn): raise UserActionError('Invalid en passant attack.') if not self._between( self.dst.y_label, last_move.src.y_label, last_move.dst.y_label): raise UserActionError('Invalid en passant attack.') self._en_passant_attack_dst = last_move.dst def _between(self, value, first, second): if first < second: return first < value < second return second < value < first def _should_disable_queenside_castlings(self): is_white_turn = self._session.is_white_turn return isinstance(self.piece, King) or ( isinstance(self.piece, Rook) and ( (self.src.loc_label == 'a1' and is_white_turn) or (self.src.loc_label == 'a8' and not is_white_turn))) def _should_disable_kingside_castlings(self): is_white_turn = self._session.is_white_turn return isinstance(self.piece, King) or ( isinstance(self.piece, Rook) and ( (self.src.loc_label == 'h1' and is_white_turn) or (self.src.loc_label == 'h8' and not is_white_turn)))
def test_get_path_raising_error(self, src_label, dst_label): src = Location(src_label) dst = Location(dst_label) with self.assertRaises(UserActionError): src.get_path(dst)