class Chess:
    def __init__(self):
        self.board = [
            ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
            ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
            [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
            [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
            ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
            ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
        ]
        self.turn = 'white'
        self.castling = {'white': {'kingside': True, 'queenside': True},
                         'black': {'kingside': True, 'queenside': True}}
        self.en_passant = None
        self.halfmove_clock = 0
        self.fullmove_number = 1
        self.king_pos = {'white': (7, 4), 'black': (0, 4)}
        self.game_over = False

    def print_board(self):
        print("  a b c d e f g h")
        print(" +-----------------+")
        for i, row in enumerate(self.board):
            print(f"{8-i}|{' '.join(row)}|{8-i}")
        print(" +-----------------+")
        print("  a b c d e f g h")
        print(f"Turn: {self.turn}")
        if self.is_in_check('white'):
            print("White is in check")
        if self.is_in_check('black'):
            print("Black is in check")

    def parse_move(self, move_str):
        parts = move_str.split()
        if len(parts) != 2:
            return None
        from_sq, to_sq = parts
        if len(from_sq) != 2 or len(to_sq) != 2:
            return None
        from_col, from_row = from_sq[0], from_sq[1]
        to_col, to_row = to_sq[0], to_sq[1]
        if not (from_col in 'abcdefgh' and from_row in '12345678'):
            return None
        if not (to_col in 'abcdefgh' and to_row in '12345678'):
            return None
        from_x, from_y = 8 - int(from_row), ord(from_col) - ord('a')
        to_x, to_y = 8 - int(to_row), ord(to_col) - ord('a')
        return (from_x, from_y), (to_x, to_y)

    def is_legal_move(self, from_pos, to_pos):
        x1, y1 = from_pos
        x2, y2 = to_pos
        piece = self.board[x1][y1]
        if piece == ' ':
            return False
        color = 'white' if piece.isupper() else 'black'
        if color != self.turn:
            return False
        if (x2, y2) == self.king_pos[color]:
            return False
        if self.board[x2][y2] != ' ':
            target_color = 'white' if self.board[x2][y2].isupper() else 'black'
            if target_color == color:
                return False
        dx, dy = x2 - x1, y2 - y1
        piece_type = piece.lower()
        if piece_type == 'p':
            return self.is_legal_pawn_move(from_pos, to_pos)
        elif piece_type == 'n':
            return abs(dx) == 2 and abs(dy) == 1 or abs(dx) == 1 and abs(dy) == 2
        elif piece_type == 'b':
            return abs(dx) == abs(dy) and self.is_path_clear(from_pos, to_pos)
        elif piece_type == 'r':
            return (dx == 0 or dy == 0) and self.is_path_clear(from_pos, to_pos)
        elif piece_type == 'q':
            return ((abs(dx) == abs(dy) or dx == 0 or dy == 0) and
                    self.is_path_clear(from_pos, to_pos))
        elif piece_type == 'k':
            return (abs(dx) <= 1 and abs(dy) <= 1) or self.is_legal_castle(from_pos, to_pos)
        return False

    def is_legal_pawn_move(self, from_pos, to_pos):
        x1, y1 = from_pos
        x2, y2 = to_pos
        piece = self.board[x1][y1]
        color = 'white' if piece.isupper() else 'black'
        direction = -1 if color == 'white' else 1
        dx, dy = x2 - x1, y2 - y1
        if dy == 0:
            if dx == direction:
                return self.board[x2][y2] == ' '
            elif dx == 2 * direction:
                start_row = 6 if color == 'white' else 1
                return (x1 == start_row and self.board[x1 + direction][y1] == ' ' and
                        self.board[x2][y2] == ' ')
        elif abs(dy) == 1 and dx == direction:
            if self.board[x2][y2] != ' ':
                return True
            if (x2, y2) == self.en_passant:
                return True
        return False

    def is_legal_castle(self, from_pos, to_pos):
        x1, y1 = from_pos
        x2, y2 = to_pos
        color = 'white' if self.board[x1][y1].isupper() else 'black'
        if self.is_in_check(color):
            return False
        if color == 'white':
            if x1 != 7 or y1 != 4:
                return False
            if to_pos == (7, 6) and self.castling['white']['kingside']:
                return (self.board[7][5] == ' ' and self.board[7][6] == ' ' and
                        not self.is_square_attacked((7, 5), 'black') and
                        not self.is_square_attacked((7, 6), 'black'))
            elif to_pos == (7, 2) and self.castling['white']['queenside']:
                return (self.board[7][1] == ' ' and self.board[7][2] == ' ' and
                        self.board[7][3] == ' ' and
                        not self.is_square_attacked((7, 3), 'black') and
                        not self.is_square_attacked((7, 2), 'black'))
        else:
            if x1 != 0 or y1 != 4:
                return False
            if to_pos == (0, 6) and self.castling['black']['kingside']:
                return (self.board[0][5] == ' ' and self.board[0][6] == ' ' and
                        not self.is_square_attacked((0, 5), 'white') and
                        not self.is_square_attacked((0, 6), 'white'))
            elif to_pos == (0, 2) and self.castling['black']['queenside']:
                return (self.board[0][1] == ' ' and self.board[0][2] == ' ' and
                        self.board[0][3] == ' ' and
                        not self.is_square_attacked((0, 3), 'white') and
                        not self.is_square_attacked((0, 2), 'white'))
        return False

    def is_path_clear(self, from_pos, to_pos):
        x1, y1 = from_pos
        x2, y2 = to_pos
        dx, dy = x2 - x1, y2 - y1
        step_x = 1 if dx > 0 else -1 if dx < 0 else 0
        step_y = 1 if dy > 0 else -1 if dy < 0 else 0
        x, y = x1 + step_x, y1 + step_y
        while (x, y) != (x2, y2):
            if self.board[x][y] != ' ':
                return False
            x += step_x
            y += step_y
        return True

    def is_square_attacked(self, pos, attacker_color):
        x, y = pos
        for i in range(8):
            for j in range(8):
                piece = self.board[i][j]
                if piece == ' ':
                    continue
                piece_color = 'white' if piece.isupper() else 'black'
                if piece_color != attacker_color:
                    continue
                if self.is_legal_move((i, j), (x, y)):
                    return True
        return False

    def is_in_check(self, color):
        return self.is_square_attacked(self.king_pos[color], 'black' if color == 'white' else 'white')

    def make_move(self, from_pos, to_pos):
        x1, y1 = from_pos
        x2, y2 = to_pos
        piece = self.board[x1][y1]
        color = 'white' if piece.isupper() else 'black'
        if not self.is_legal_move(from_pos, to_pos):
            return False
        new_board = [row[:] for row in self.board]
        new_board[x2][y2] = new_board[x1][y1]
        new_board[x1][y1] = ' '
        if piece.lower() == 'k':
            self.castling[color]['kingside'] = False
            self.castling[color]['queenside'] = False
            self.king_pos[color] = (x2, y2)
        elif piece.lower() == 'r':
            if color == 'white':
                if (x1, y1) == (7, 0):
                    self.castling['white']['queenside'] = False
                elif (x1, y1) == (7, 7):
                    self.castling['white']['kingside'] = False
            else:
                if (x1, y1) == (0, 0):
                    self.castling['black']['queenside'] = False
                elif (x1, y1) == (0, 7):
                    self.castling['black']['kingside'] = False
        if piece.lower() == 'p':
            self.halfmove_clock = 0
            if abs(x2 - x1) == 2:
                self.en_passant = (x1 + (1 if color == 'black' else -1), y1)
            else:
                self.en_passant = None
            if (x2, y2) == self.en_passant:
                new_board[x1][y2] = ' '
        else:
            self.halfmove_clock += 1
            self.en_passant = None
        if piece.lower() == 'p' and (x2 == 0 or x2 == 7):
            new_board[x2][y2] = 'Q' if color == 'white' else 'q'
        if self.is_in_check(color):
            return False
        self.board = new_board
        if self.is_in_check('black' if color == 'white' else 'white'):
            if self.is_checkmate('black' if color == 'white' else 'white'):
                print(f"Checkmate! {color} wins!")
                self.game_over = True
            else:
                print(f"Check! {color} is in check.")
        elif self.is_stalemate('black' if color == 'white' else 'white'):
            print("Stalemate! The game is a draw.")
            self.game_over = True
        self.turn = 'black' if color == 'white' else 'white'
        if color == 'black':
            self.fullmove_number += 1
        return True

    def is_checkmate(self, color):
        for i in range(8):
            for j in range(8):
                piece = self.board[i][j]
                if piece == ' ':
                    continue
                piece_color = 'white' if piece.isupper() else 'black'
                if piece_color != color:
                    continue
                for x in range(8):
                    for y in range(8):
                        if self.is_legal_move((i, j), (x, y)):
                            return False
        return self.is_in_check(color)

    def is_stalemate(self, color):
        for i in range(8):
            for j in range(8):
                piece = self.board[i][j]
                if piece == ' ':
                    continue
                piece_color = 'white' if piece.isupper() else 'black'
                if piece_color != color:
                    continue
                for x in range(8):
                    for y in range(8):
                        if self.is_legal_move((i, j), (x, y)):
                            return False
        return not self.is_in_check(color)

    def play(self):
        while not self.game_over:
            self.print_board()
            move_str = input(f"{self.turn}'s move (e.g., e2 e4): ")
            move = self.parse_move(move_str)
            if move is None:
                print("Invalid move format. Use format like 'e2 e4'")
                continue
            from_pos, to_pos = move
            if not self.make_move(from_pos, to_pos):
                print("Illegal move. Try again.")
        self.print_board()

if __name__ == "__main__":
    game = Chess()
    game.play()
