예제 #1
0
파일: grid.py 프로젝트: Nieminik/pychess
    def castle(self, color, side=Side.Kingside):
        """Perform a castle."""
        grid = deepcopy(self)
        king = next(
            (x for x in grid._pieces[piece_types.King] if x.color is color))

        rook_f = 7 if side is Side.Kingside else 0
        rook = grid[Position(king.position.rank, rook_f)]

        if not rook or not isinstance(rook, piece_types.Rook):
            return False

        if king.moves or rook.moves:
            return False

        direction = int(math.copysign(1, rook_f - king.position.file))
        move_pos = king.position + Position(0, direction)

        if grid[move_pos] or not self.move(rook.position, move_pos):
            return False

        grid._pieces[piece_types.Rook].remove(rook)
        for _ in range(2):
            moved = grid.move(king.position,
                              king.position + Position(0, direction))
            if not moved:
                return False

        grid._pieces[piece_types.Rook].append(rook)

        self._pieces = grid._pieces
        return True
예제 #2
0
def test_attack_range(pawn):  # noqa: D103
    dir_val = pawn.get_direction(pawn).value
    grid = pawn.grid

    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=True)

    p2_pos = pawn.position + Position(dir_val, -1)
    grid.add_piece(pieces.Pawn(p2_pos, pawn.color))
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=False,
                                                          right=True)

    p3_pos = pawn.position + Position(dir_val, 1)
    grid.add_piece(pieces.Pawn(p3_pos, pawn.color))
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=False,
                                                          right=False)

    grid[p2_pos].color = grid[p2_pos].color.inverted()
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=False)

    grid[p3_pos].color = grid[p3_pos].color.inverted()
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=True)
예제 #3
0
def test_an_passant(pawn):  # noqa: D103
    grid = pawn.grid

    p2_pos = pawn.position + Position(0, -1)
    grid.add_piece(pieces.Pawn(p2_pos, pawn.color))

    grid[p2_pos].previous_positions = [None]
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=True)

    grid[p2_pos].color = pawn.color.inverted()
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=True)

    grid[p2_pos].previous_positions = []
    assert pawn.attack_range == get_expected_attack_range(pawn,
                                                          left=True,
                                                          right=True)

    p3_pos = pawn.position + Position(0, 1)
    attacked_pos = p3_pos + Position(pawn.get_direction(pawn).value, 0)
    grid.add_piece(pieces.Pawn(p3_pos, pawn.color.inverted()))
    grid[p3_pos].previous_positions = [None]

    other = grid[p3_pos]
    assert grid.move(pawn.position, attacked_pos)
    assert grid.captured == [other]
예제 #4
0
def test_knight_ranges(color, coords, knight):  # noqa: D103
    knight.position = Position(*coords)
    knight.color = color

    assert sorted(knight.move_range) == sorted(knight.attack_range)

    move_diffs = [(1, 2), (1, -2), (-1, 2), (-1, -2)]
    move_diffs += list(map(reversed, move_diffs))
    move_diffs = map(lambda x: Position(*x), move_diffs)
    moves = map(lambda x: x + knight.position, move_diffs)
    moves = list(filter(lambda x: x.is_valid(), moves))
    assert sorted(knight.move_range) == sorted(moves)

    pos = knight.position + Position(1, 2)
    pawn = pieces.Pawn(pos, color=color)
    knight.grid.add_piece(pawn)

    try:
        moves.remove(pawn.position)
    except ValueError:
        pass
    assert sorted(knight.move_range) == sorted(moves)

    pawn.color = pawn.color.inverted()
    if pawn.position.is_valid():
        moves.append(pawn.position)
    assert sorted(knight.move_range) == sorted(moves)
예제 #5
0
def get_expected_move_range(pawn, two_positions=False):
    """Get expected move range."""
    r, f = pawn.position
    dir_val = pieces.Pawn.get_direction(pawn).value
    expected = [Position(r + dir_val, f)]
    if two_positions:
        expected.append(Position(r + dir_val * 2, f))
    return expected
예제 #6
0
def test_bishop_incorrect_move(wrong_pos_coords, bishop):  # noqa: D103
    assert not bishop.move(bishop.position)
    assert not bishop.move(bishop.position + Position(*wrong_pos_coords))

    assert not bishop.move(Position(MAX_POS, bishop.position.file))
    assert not bishop.move(Position(-1, bishop.position.file))
    assert not bishop.move(Position(bishop.position.rank, MAX_POS))
    assert not bishop.move(Position(bishop.position.rank, -1))
예제 #7
0
def test_king_incorrect_move(wrong_pos_coords, king):  # noqa: D103
    assert not king.move(king.position)
    assert not king.move(Position(*wrong_pos_coords) + king.position)

    assert not king.move(Position(MAX_POS, king.position.file))
    assert not king.move(Position(-1, king.position.file))
    assert not king.move(Position(king.position.rank, MAX_POS))
    assert not king.move(Position(king.position.rank, -1))
예제 #8
0
def test_rook_incorrect_move(wrong_pos_coords, rook):  # noqa: D103
    assert not rook.move(rook.position)
    assert not rook.move(rook.position + Position(*wrong_pos_coords))

    assert not rook.move(Position(MAX_POS, rook.position.file))
    assert not rook.move(Position(-1, rook.position.file))
    assert not rook.move(Position(rook.position.rank, MAX_POS))
    assert not rook.move(Position(rook.position.rank, -1))
예제 #9
0
def test_knight_incorrect_move(wrong_pos_coords, knight):  # noqa: D103
    assert not knight.move(knight.position)
    assert not knight.move(knight.position + Position(*wrong_pos_coords))

    assert not knight.move(Position(MAX_POS, knight.position.file))
    assert not knight.move(Position(-1, knight.position.file))
    assert not knight.move(Position(knight.position.rank, MAX_POS))
    assert not knight.move(Position(knight.position.rank, -1))
예제 #10
0
def test_pawn_empty_range(pawn):  # noqa: D103
    pawn.position = Position(7, 5)
    pawn.color = Color.White
    assert pawn.move_range == []

    pawn.position = Position(0, 5)
    pawn.color = Color.Black
    assert pawn.move_range == []
예제 #11
0
def test_queen_incorrect_move(wrong_pos_coords, queen):  # noqa: D103
    assert not queen.move(queen.position)
    assert not queen.move(Position(*wrong_pos_coords) + queen.position)

    assert not queen.move(Position(MAX_POS, queen.position.file))
    assert not queen.move(Position(-1, queen.position.file))
    assert not queen.move(Position(queen.position.rank, MAX_POS))
    assert not queen.move(Position(queen.position.rank, -1))
예제 #12
0
def test_vertical_center(piece):  # noqa: D103
    start_pos = piece.position
    ver = vertical(piece)
    p1 = Position(*next(ver))
    assert p1.file == start_pos.file

    p2 = Position(*next(ver))
    assert p2.file == start_pos.file
    expected = [start_pos.rank - 1, start_pos.rank + 1]
    assert sorted((p1.rank, p2.rank)) == expected
예제 #13
0
def test_horizontal_center(piece):  # noqa: D103
    start_pos = piece.position
    hor = horizontal(piece)
    p1 = Position(*next(hor))
    assert p1.rank == start_pos.rank

    p2 = Position(*next(hor))
    assert p2.rank == start_pos.rank
    expected = [start_pos.file - 1, start_pos.file + 1]
    assert sorted((p1.file, p2.file)) == expected
예제 #14
0
def test_in_check(grid):  # noqa: D103
    king = piece_types.King(Position(0, 0))
    rook = piece_types.Rook(Position(0, 1), Color.Black)

    assert not grid.own_king_in_check(king)

    grid.add_piece(king)
    grid.add_piece(rook)
    assert grid.own_king_in_check(king)

    grid.report_capture(rook)
    assert not grid.own_king_in_check(king)
예제 #15
0
def test_vertical_edge(p_rank, piece):  # noqa: D103
    piece.position = Position(p_rank, piece.position.file)
    start_pos = piece.position
    ver = vertical(piece)
    p1 = Position(*next(ver))
    diff = 1 if p_rank == MIN_POS else -1

    assert p1.file == start_pos.file
    assert p1.rank == start_pos.rank + diff

    p2 = Position(*next(ver))
    assert p2.file == start_pos.file
    assert p2.rank == start_pos.rank + diff * 2
예제 #16
0
    def attack_range(self):
        """Get an attack range for pawn."""
        r, f = self.position
        n_rank = r + self.get_direction(self).value
        rng = []

        for n_file in (f + 1, f - 1):
            pos = Position(n_rank, n_file)
            other = self.grid[pos]
            if pos.is_valid() and (not other or other.color != self.color):
                rng.append(pos)

        return rng
예제 #17
0
def _pos_iter(piece, transformation):
    """Iterate through positions based on the given transformation function."""
    pos = piece.position
    while True:
        pos = Position(*transformation(*pos))
        if not pos.is_valid():
            break
        other_piece = piece.grid[pos]
        if other_piece:
            if other_piece.color != piece.color and piece.move_attacks:
                yield pos
            break
        yield pos
예제 #18
0
def test_horizontal_edge(p_file, piece):  # noqa: D103
    piece.position = Position(piece.position.rank, p_file)
    start_pos = piece.position
    hor = horizontal(piece)
    p1 = Position(*next(hor))
    diff = 1 if p_file == MIN_POS else -1

    assert p1.file == start_pos.file + diff
    assert p1.rank == start_pos.rank

    p2 = Position(*next(hor))
    assert p2.file == start_pos.file + diff * 2
    assert p2.rank == start_pos.rank
예제 #19
0
    def move(self, position):  # noqa: D102
        new_pos = Position(*position)

        if not new_pos.is_valid():
            return False

        if position == self.position:
            return False

        if new_pos not in self.move_range + self.attack_range:
            return False

        self.previous_positions.append(self.position)
        self.position = position
        return True
예제 #20
0
def test_queen_ranges(coords, queen):  # noqa: D103
    queen.position = Position(*coords)

    exp_ranges = chain(diagonal(queen), horizontal(queen), vertical(queen))

    assert sorted(queen.move_range) == sorted(queen.attack_range)
    assert sorted(exp_ranges) == sorted(queen.move_range)
예제 #21
0
 def __init__(self, position, color=Color.White):
     self.position = Position(*position)
     self.color = color
     self.grid = None
     self.move_attacks = True
     self._mv_range = []
     self.previous_positions = []
예제 #22
0
def collision_setup(piece):  # noqa: D103
    grid = piece.grid
    p2 = Piece(piece.position + Position(0, 1), piece.color)
    grid.add_piece(piece)
    grid.add_piece(p2)
    r = right(piece)
    return piece, p2, r
예제 #23
0
def test_king_ranges(coords, king):  # noqa: D103
    king.position = Position(*coords)

    exp_ranges = chain(diagonal(king, 4), horizontal(king, 2),
                       vertical(king, 2))

    assert sorted(king.move_range) == sorted(king.attack_range)
    assert sorted(exp_ranges) == sorted(king.move_range)
예제 #24
0
def test_move_in_check():  # noqa: D103
    grid = Grid()
    r, f = 1, 1
    king = piece_types.King(Position(r, f - 1))
    rook = piece_types.Rook(Position(r, f + 1), color=Color.Black)
    p1 = piece_types.Pawn(Position(r - 1, f))
    p2 = piece_types.Pawn(Position(r - 1, f + 2))

    for piece in (king, rook, p1, p2):
        grid.add_piece(piece)

    assert grid.own_king_in_check(king)

    assert not grid.move(p2.position, p2.position + Position(1, 0))

    assert grid.move(p1.position, p1.position + Position(1, 0))
    assert not grid.own_king_in_check(king)

    p1.position += Position(-1, 0)

    print(king, p2, rook)
    assert grid.own_king_in_check(king)
    assert grid.move(p2.position, rook.position)

    assert not grid.own_king_in_check(king)
예제 #25
0
def prepare_pieces(pieces_notations, color):
    """Prepare pieces for color."""
    iters = []
    for piece_cls, notations in pieces_notations.items():
        pieces = list(
            map(lambda n: piece_cls(Position.get_pos(n), color), notations))
        iters.append(pieces)

    return chain.from_iterable(iters)
예제 #26
0
def test_pawn_move_range(r, f, color, pawn):  # noqa: D103
    pawn.position = Position(r, f)
    pawn.color = color
    assert pawn.move_range == get_expected_move_range(pawn, True)

    start_pos = pawn.position
    pawn.move(next(iter(pawn.move_range)))
    pawn.position = start_pos
    assert pawn.move_range == get_expected_move_range(pawn, False)
예제 #27
0
def test_revert_move(piece):  # noqa: D103
    positions = [piece.position]

    for _ in range(3):
        piece.move(piece.position + Position(1, 0))
        positions.append(piece.position)

    while positions:
        assert positions.pop() == piece.position
        piece.revert_move()
예제 #28
0
def test_piece_eq(piece):  # noqa: D103
    other = deepcopy(piece)
    assert other == piece

    other.color = other.color.inverted()
    assert other != piece

    other = deepcopy(piece)
    other.position = other.position + Position(1, 1)
    assert other != piece
예제 #29
0
def test_castle_attacking_bishop(color, side, grid_castle):  # noqa: D103
    kings = grid_castle._pieces[piece_types.King]
    king = next(filter(lambda p: p.color == color, kings))
    direction = 1 if color is Color.White else -1

    bishop = piece_types.Bishop(king.position + Position(direction, 0),
                                color.inverted())

    grid_castle.add_piece(bishop)
    assert not grid_castle.castle(color, side)
예제 #30
0
def test_castle_piece_between(color, file_letter, grid_castle):  # noqa: D103
    rank = 1 if color is Color.White else 8

    side = Side.Queenside if file_letter in "bcd" else Side.Kingside

    pawn = piece_types.Pawn(Position.get_pos(f"{file_letter}{rank}"),
                            color=color.White)
    grid_castle.add_piece(pawn)

    assert not grid_castle.castle(color, side)