Exemple #1
0
class Example(QtGui.QWidget):
    
    board_text_space = 15
    min_board_sz = 80
    hit_cell_color = "red"
    move_cell_color = "green"
    hit_and_move_cell_color = "orange"
    piece_cell_color = "yellow"

    img_path = os.path.join(self_dir, "chess_piece")

    piece_fname_mapping = {
        "WQ": "white_quinn",
        "WK": "white_king",
        "WP": "white_pawn",
        "WN": "white_knight",
        "WR": "white_rook",
        "WB": "white_bishop",
        "BQ": "black_quinn",
        "BK": "black_king",
        "BP": "black_pawn",
        "BN": "black_knight",
        "BR": "black_rook",
        "BB": "black_bishop",
    }

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()
        self.font = QtGui.QFont("times", 24)
        self.chess_piece_font = QtGui.QFont("console", 30)
        self.fm = QtGui.QFontMetrics(self.font)
        self.chess_piece_fm = QtGui.QFontMetrics(self.chess_piece_font)
        self.vertical_lines_x_corrds = []
        self.horizontal_lines_y_coords = []

        self.board = Board(knorre_vs_neumann())

        self.pieces_images = {}
        self.load_pieces(self.img_path)

        self.active_cell = None
        self.selected_piece = None

    def cell_to_coords(self, cell):
        return self.cell_index_to_coords(*to_tuple_pos(cell))

    def cell_index_to_coords(self, cell_x, cell_y):
        cell_y = 7 - cell_y
        x1, x2 = self.vertical_lines_x_corrds[cell_x: cell_x + 2]
        y1, y2 = self.horizontal_lines_y_coords[cell_y: cell_y + 2]
        return x1, y1, x2 - x1, y2 - y1

    def load_pieces(self, path):
        for key, fname in self.piece_fname_mapping.items():
            img = QtGui.QImage()
            img.load(os.path.join(path, fname))
            self.pieces_images[key] = img

    def initUI(self):      
        self.setGeometry(300, 300, 800, 800)
        self.setWindowTitle('Chess GUI')
        self.show()

    def paintEvent(self, event):
        qp = QtGui.QPainter()
        qp.begin(self)
        self.draw_board(qp)

    def get_cell_from_abs_pos(self, x, y):
        if x < self.vertical_lines_x_corrds[0] or x > self.vertical_lines_x_corrds[-1]:
            return False, None, None

        if y < self.horizontal_lines_y_coords[0] or y > self.horizontal_lines_y_coords[-1]:
            return False, None, None

        for xpos, cx in enumerate(self.vertical_lines_x_corrds[1:]):
            if x < cx:
                break

        for ypos, cy in enumerate(self.horizontal_lines_y_coords[1:]):
            if y < cy:
                break

        return True, xpos, 7 - ypos

    def mousePressEvent(self, event):
        ok, xpos, ypos = self.get_cell_from_abs_pos(event.pos().x(), event.pos().y())
        if ok:
            piece = self.board.get((xpos, ypos))
            if piece is not None:
                self.selected_piece = piece
            else:
                self.selected_piece = None
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if self.selected_piece is not None:
            ok, xpos, ypos = self.get_cell_from_abs_pos(event.pos().x(), event.pos().y())
            if ok:
                #piece = self.board.get((xpos, ypos))
                self.selected_piece.move((xpos, ypos))
            else:
                self.selected_piece = None
            self.repaint()
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def mouseReleaseEvent(self, event):
        ok, xpos, ypos = self.get_cell_from_abs_pos(event.pos().x(), event.pos().y())
        self.selected_piece = None

        if ok:
            self.on_cell_clicked(xpos, ypos)
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def on_cell_clicked(self, xpos, ypos):
        self.active_cell = (xpos, ypos)
        self.repaint()

    def draw_board(self, painter):

        # calculate sizes
        sz = self.geometry().size()
        painter.setFont(self.font)

        text_h = self.fm.height()
        text_w = max(map(self.fm.width, "12345678"))

        board_sz = min(sz.height() - text_h - self.board_text_space * 3, 
                       sz.width() - text_w - self.board_text_space * 3)

        board_and_text_w = text_w + self.board_text_space + board_sz
        board_and_text_h = text_h + self.board_text_space + board_sz

        y_start_pos = (sz.height() - board_and_text_h) / 2
        x_start_pos = (sz.width() - board_and_text_w) / 2

        step = float(board_sz) / 8
        half_step = int(step / 2)

        self.horizontal_lines_y_coords = [y_start_pos + int(i * step) for i in range(9)]
        vertical_start_x = x_start_pos + text_w + self.board_text_space
        self.vertical_lines_x_corrds = [vertical_start_x + int(i * step) for i in range(9)]

        # draw labels
        for text, curr_y in zip("87654321", self.horizontal_lines_y_coords[:-1]):
            painter.drawText(x_start_pos, curr_y + half_step + text_h / 2, text)
            #painter.drawRect(x_start_pos, curr_y - text_h, text_w, text_h)

        curr_y = y_start_pos + board_and_text_h - text_h / 2
        for text, curr_x in zip(board_letters, self.vertical_lines_x_corrds[:-1]):
            painter.drawText(curr_x + half_step - self.fm.width(text) / 2, curr_y, text)

        # draw black squares
        self.set_color(painter, lambda x, y: (x + y) % 2 == 1, "grey")

        for piece in self.board:
            tp, move, hit = piece.full_name(), self.board.get_all_moves(piece), self.board.get_all_hits(piece)

            if piece.pos == self.active_cell:
                self.draw_piece(painter, piece.pos, tp, list(move), list(hit), True)                
            else:
                self.draw_piece(painter, piece.pos, tp, "", "", False)

        self.draw_grid(painter, x_start_pos + text_w + self.board_text_space, y_start_pos, board_sz)

    def to_colored(self, piece):
        if piece[0] == "W":
            return self.white(piece[1:])
        else:
            assert piece[0] == "B"
            return self.black(piece[1:])

    def white(self, piece):
        return unicode(piece) + U"\u21D1"

    def black(self, piece):
        return unicode(piece) + U"\u21D3"

    def draw_piece(self, painter, pos, text, move_cells, hit_cells, collor_under_piece=False, use_image=True):

        hit_cells_set = set(hit_cells)
        move_cells_set =  set(move_cells)
        
        hit_only = hit_cells_set - move_cells_set
        move_only = move_cells_set - hit_cells_set
        hit_and_move = move_cells_set & hit_cells_set

        self.set_color(painter, list(hit_only), self.hit_cell_color, 125)
        self.set_color(painter, list(move_only), self.move_cell_color, 125)
        self.set_color(painter, list(hit_and_move), self.hit_and_move_cell_color, 125)

        if collor_under_piece:
            self.set_color(painter, [pos], self.piece_cell_color, 125)

        cell_x, cell_y = pos

        if not use_image:
            c = "white" if (cell_x + cell_y) % 2 == 1 else "black"
            self.draw_text(painter, pos, self.to_colored(text), c)
        else:
            x, y, w, h = self.cell_to_coords(pos)
            painter.drawImage(x + h * 0.05, y + h * 0.05, 
                              self.pieces_images[text].scaledToHeight(h * 0.9, QtCore.Qt.SmoothTransformation))


    def draw_text(self, painter, cell, text, color):
        c = QtGui.QColor(color)
        x, y, w, h = self.cell_to_coords(cell)
        painter.setFont(self.chess_piece_font)
        painter.setPen(c)
        painter.drawText(x + w / 2 - self.chess_piece_fm.width(text) / 2, 
                         y + h / 2 + self.chess_piece_fm.height() / 3, text)
        painter.setFont(self.font)
        painter.setPen(QtGui.QColor("black"))

    def draw_grid(self, painter, x_start, y_start, board_sz):
        # draw lines
        y_pairs = zip(self.horizontal_lines_y_coords[:-1], self.horizontal_lines_y_coords[1:])
        for y in self.horizontal_lines_y_coords:
            painter.drawLine(x_start, y, x_start + board_sz, y)

        for x in self.vertical_lines_x_corrds:
            painter.drawLine(x, y_start, x, y_start + board_sz)


    def set_color(self, painter, filter_func, color, alpha=255):
        if isinstance(filter_func, list):
            if len(filter_func) == 0:
                return

            filter_array = filter_func
            filter_func = lambda x, y: (x, y) in filter_array

        c = QtGui.QColor(color)
        c.setAlpha(alpha)

        for x_cell_p in range(8):
            for y_cell_p in range(8):
                if filter_func(x_cell_p, y_cell_p):
                    x, y, w, h = self.cell_index_to_coords(x_cell_p, y_cell_p)
                    painter.fillRect(x, y, w, h, c)
Exemple #2
0
class Example(QtGui.QWidget):

    board_text_space = 15
    min_board_sz = 80
    hit_cell_color = "red"
    move_cell_color = "green"
    hit_and_move_cell_color = "orange"
    piece_cell_color = "yellow"

    img_path = os.path.join(self_dir, "chess_piece")

    piece_fname_mapping = {
        "WQ": "white_quinn",
        "WK": "white_king",
        "WP": "white_pawn",
        "WN": "white_knight",
        "WR": "white_rook",
        "WB": "white_bishop",
        "BQ": "black_quinn",
        "BK": "black_king",
        "BP": "black_pawn",
        "BN": "black_knight",
        "BR": "black_rook",
        "BB": "black_bishop",
    }

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()
        self.font = QtGui.QFont("times", 24)
        self.chess_piece_font = QtGui.QFont("console", 30)
        self.fm = QtGui.QFontMetrics(self.font)
        self.chess_piece_fm = QtGui.QFontMetrics(self.chess_piece_font)
        self.vertical_lines_x_corrds = []
        self.horizontal_lines_y_coords = []

        self.board = Board(knorre_vs_neumann())

        self.pieces_images = {}
        self.load_pieces(self.img_path)

        self.active_cell = None
        self.selected_piece = None

    def cell_to_coords(self, cell):
        return self.cell_index_to_coords(*to_tuple_pos(cell))

    def cell_index_to_coords(self, cell_x, cell_y):
        cell_y = 7 - cell_y
        x1, x2 = self.vertical_lines_x_corrds[cell_x:cell_x + 2]
        y1, y2 = self.horizontal_lines_y_coords[cell_y:cell_y + 2]
        return x1, y1, x2 - x1, y2 - y1

    def load_pieces(self, path):
        for key, fname in self.piece_fname_mapping.items():
            img = QtGui.QImage()
            img.load(os.path.join(path, fname))
            self.pieces_images[key] = img

    def initUI(self):
        self.setGeometry(300, 300, 800, 800)
        self.setWindowTitle('Chess GUI')
        self.show()

    def paintEvent(self, event):
        qp = QtGui.QPainter()
        qp.begin(self)
        self.draw_board(qp)

    def get_cell_from_abs_pos(self, x, y):
        if x < self.vertical_lines_x_corrds[
                0] or x > self.vertical_lines_x_corrds[-1]:
            return False, None, None

        if y < self.horizontal_lines_y_coords[
                0] or y > self.horizontal_lines_y_coords[-1]:
            return False, None, None

        for xpos, cx in enumerate(self.vertical_lines_x_corrds[1:]):
            if x < cx:
                break

        for ypos, cy in enumerate(self.horizontal_lines_y_coords[1:]):
            if y < cy:
                break

        return True, xpos, 7 - ypos

    def mousePressEvent(self, event):
        ok, xpos, ypos = self.get_cell_from_abs_pos(event.pos().x(),
                                                    event.pos().y())
        if ok:
            piece = self.board.get((xpos, ypos))
            if piece is not None:
                self.selected_piece = piece
            else:
                self.selected_piece = None
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if self.selected_piece is not None:
            ok, xpos, ypos = self.get_cell_from_abs_pos(
                event.pos().x(),
                event.pos().y())
            if ok:
                #piece = self.board.get((xpos, ypos))
                self.selected_piece.move((xpos, ypos))
            else:
                self.selected_piece = None
            self.repaint()
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def mouseReleaseEvent(self, event):
        ok, xpos, ypos = self.get_cell_from_abs_pos(event.pos().x(),
                                                    event.pos().y())
        self.selected_piece = None

        if ok:
            self.on_cell_clicked(xpos, ypos)
        else:
            return super(Example, self).mouseReleaseEvent(event)

    def on_cell_clicked(self, xpos, ypos):
        self.active_cell = (xpos, ypos)
        self.repaint()

    def draw_board(self, painter):

        # calculate sizes
        sz = self.geometry().size()
        painter.setFont(self.font)

        text_h = self.fm.height()
        text_w = max(map(self.fm.width, "12345678"))

        board_sz = min(sz.height() - text_h - self.board_text_space * 3,
                       sz.width() - text_w - self.board_text_space * 3)

        board_and_text_w = text_w + self.board_text_space + board_sz
        board_and_text_h = text_h + self.board_text_space + board_sz

        y_start_pos = (sz.height() - board_and_text_h) / 2
        x_start_pos = (sz.width() - board_and_text_w) / 2

        step = float(board_sz) / 8
        half_step = int(step / 2)

        self.horizontal_lines_y_coords = [
            y_start_pos + int(i * step) for i in range(9)
        ]
        vertical_start_x = x_start_pos + text_w + self.board_text_space
        self.vertical_lines_x_corrds = [
            vertical_start_x + int(i * step) for i in range(9)
        ]

        # draw labels
        for text, curr_y in zip("87654321",
                                self.horizontal_lines_y_coords[:-1]):
            painter.drawText(x_start_pos, curr_y + half_step + text_h / 2,
                             text)
            #painter.drawRect(x_start_pos, curr_y - text_h, text_w, text_h)

        curr_y = y_start_pos + board_and_text_h - text_h / 2
        for text, curr_x in zip(board_letters,
                                self.vertical_lines_x_corrds[:-1]):
            painter.drawText(curr_x + half_step - self.fm.width(text) / 2,
                             curr_y, text)

        # draw black squares
        self.set_color(painter, lambda x, y: (x + y) % 2 == 1, "grey")

        for piece in self.board:
            tp, move, hit = piece.full_name(), self.board.get_all_moves(
                piece), self.board.get_all_hits(piece)

            if piece.pos == self.active_cell:
                self.draw_piece(painter, piece.pos, tp, list(move), list(hit),
                                True)
            else:
                self.draw_piece(painter, piece.pos, tp, "", "", False)

        self.draw_grid(painter, x_start_pos + text_w + self.board_text_space,
                       y_start_pos, board_sz)

    def to_colored(self, piece):
        if piece[0] == "W":
            return self.white(piece[1:])
        else:
            assert piece[0] == "B"
            return self.black(piece[1:])

    def white(self, piece):
        return unicode(piece) + U"\u21D1"

    def black(self, piece):
        return unicode(piece) + U"\u21D3"

    def draw_piece(self,
                   painter,
                   pos,
                   text,
                   move_cells,
                   hit_cells,
                   collor_under_piece=False,
                   use_image=True):

        hit_cells_set = set(hit_cells)
        move_cells_set = set(move_cells)

        hit_only = hit_cells_set - move_cells_set
        move_only = move_cells_set - hit_cells_set
        hit_and_move = move_cells_set & hit_cells_set

        self.set_color(painter, list(hit_only), self.hit_cell_color, 125)
        self.set_color(painter, list(move_only), self.move_cell_color, 125)
        self.set_color(painter, list(hit_and_move),
                       self.hit_and_move_cell_color, 125)

        if collor_under_piece:
            self.set_color(painter, [pos], self.piece_cell_color, 125)

        cell_x, cell_y = pos

        if not use_image:
            c = "white" if (cell_x + cell_y) % 2 == 1 else "black"
            self.draw_text(painter, pos, self.to_colored(text), c)
        else:
            x, y, w, h = self.cell_to_coords(pos)
            painter.drawImage(
                x + h * 0.05, y + h * 0.05,
                self.pieces_images[text].scaledToHeight(
                    h * 0.9, QtCore.Qt.SmoothTransformation))

    def draw_text(self, painter, cell, text, color):
        c = QtGui.QColor(color)
        x, y, w, h = self.cell_to_coords(cell)
        painter.setFont(self.chess_piece_font)
        painter.setPen(c)
        painter.drawText(x + w / 2 - self.chess_piece_fm.width(text) / 2,
                         y + h / 2 + self.chess_piece_fm.height() / 3, text)
        painter.setFont(self.font)
        painter.setPen(QtGui.QColor("black"))

    def draw_grid(self, painter, x_start, y_start, board_sz):
        # draw lines
        y_pairs = zip(self.horizontal_lines_y_coords[:-1],
                      self.horizontal_lines_y_coords[1:])
        for y in self.horizontal_lines_y_coords:
            painter.drawLine(x_start, y, x_start + board_sz, y)

        for x in self.vertical_lines_x_corrds:
            painter.drawLine(x, y_start, x, y_start + board_sz)

    def set_color(self, painter, filter_func, color, alpha=255):
        if isinstance(filter_func, list):
            if len(filter_func) == 0:
                return

            filter_array = filter_func
            filter_func = lambda x, y: (x, y) in filter_array

        c = QtGui.QColor(color)
        c.setAlpha(alpha)

        for x_cell_p in range(8):
            for y_cell_p in range(8):
                if filter_func(x_cell_p, y_cell_p):
                    x, y, w, h = self.cell_index_to_coords(x_cell_p, y_cell_p)
                    painter.fillRect(x, y, w, h, c)