Exemplo n.º 1
0
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)))
Exemplo n.º 2
0
 def test_get_vector(self, src_label, dst_label, expected_vector):
     src = Location(src_label)
     dst = Location(dst_label)
     actual_vector = src.get_vector(dst)
     self.assertIsInstance(actual_vector, tuple)
     self.assertEqual(actual_vector, expected_vector)