Exemple #1
0
 def end_flash(self):
     # 游戏结束时的闪烁操作
     if self.flash_cnt <= 5:
         # 执行闪烁
         self.flash_cnt += 1
         self.repaint()
     else:
         # 闪烁完毕,执行重新开始的操作
         self.end_timer.stop()
         # 1. 显示游戏结束的信息
         if self.res == 1:
             QMessageBox.about(self, '游戏结束', '玩家获胜!')
         elif self.res == 2:
             QMessageBox.about(self, '游戏结束', '电脑获胜!')
         elif self.res == 3:
             QMessageBox.about(self, '游戏结束', '平局!')
         else:
             raise ValueError('当前游戏结束的标志位为' + self.res +
                              '. 而游戏结束的标志位必须为1, 2 或 3')
         # 2. 游戏重新开始的操作
         self.res = 0
         self.operate_status = 0
         self.flash_cnt = 0
         self.g = Gomoku()  # 重新初始化游戏内容
         self.repaint(0, 0, 650, 650)  # 重新绘制游戏界面
Exemple #2
0
    def __init__(self):
        super().__init__()
        self.init_ui()  # 初始化游戏界面
        self.g = Gomoku()  # 初始化游戏内容

        self.last_pos = (-1, -1)
        self.res = 0  # 记录那边获得了胜利
        self.operate_status = 0  # 游戏操作状态。0为游戏中(可操作),1为游戏结束闪烁过程中(不可操作)
Exemple #3
0
    def start_game(self):
        # return to hall after the match
        # if return to room, must init socket, reset the to_influence by calling hook()
        #hall_hook = self.hall_hook

        self.game_board = Gomoku(self.is_master, self.room_name,\
                                self.master_name, self.guest_name,\
                                self.master_stone, self.server_ip,\
                                self.web_socket, self.hall_hook)
        self.game_board.show()
        self.close()
Exemple #4
0
    def watch_game(self):
        """call by action_btn, watch a match in certain room"""
        selected_row = self.rooms_observed.currentRow()
        master_name = self.room_list[selected_row + self.current_page * 10]["master"]
        guest_name = self.room_list[selected_row + self.current_page * 10]["guest"]
        room_name = self.rooms_observed.item(selected_row, 0).text()

        uri = 'ws://' + self.server_ip + ':8080/playing'

        socket_headers = [("role", 'a'),\
            ("roomName", room_name),\
            ("userName", self.username),\
            ("masterStone", 1)]

        self.web_socket = SocketCli(uri, headers=socket_headers)
        # self.web_socket.hook(self)

        self.game_board = Gomoku(True, room_name, master_name,\
            guest_name, 1, self.server_ip, self.web_socket,\
            self.hall_hook, True)
        self.game_board.show()
        self.close()
Exemple #5
0
class GameRoomWindow(QWidget):

    start_game_signal = pyqtSignal()

    def __init__(self, room_name, master_name, guest_name,\
        server_ip, is_master, hall_hook, login_hook, auth_headers):
        super().__init__()

        self.auth_headers = auth_headers

        self.start_game_signal.connect(self.start_game)

        self.hall_hook = hall_hook
        self.login_hook = login_hook

        self.layout = QHBoxLayout()
        self.room_name = room_name
        self.server_ip = server_ip
        #self.user_name = user_name
        self.is_master = is_master
        self.master_stone = 1

        self.master_name = master_name
        self.guest_name = guest_name

        self.title = "Game Hall"
        self.top = 100
        self.left = 100
        self.width = 600
        self.height = 200

        self.ready = False

        self.init_socket()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.top, self.left, self.width, self.height)
        current_path = ':/'  # sys.path[0] + '/'
        self.setWindowIcon(
            QIcon(current_path +
                  'chessboard/gomoku_icon.png'))  # set window icon
        self.stone_color_label = QLabel("Creator will use:", self)
        self.stone_color_label.move(255, 14)

        self.colors = QComboBox(self)
        self.colors.addItems(["Black", "White"])
        self.colors.setGeometry(250, 40, 100, 20)
        self.colors.setEnabled(self.is_master)
        if self.is_master:
            self.colors.currentIndexChanged.connect(self.handle_color_change)

        self.start_button_label = QLabel("Start the game:", self)
        self.start_button_label.move(405, 14)

        self.start_button = QPushButton('Start', self)
        self.start_button.move(400, 34)
        self.start_button.clicked.connect(self.handle_start)
        self.start_button.setEnabled(False)

        self.leave_button_label = QLabel("Leave the game:", self)
        self.leave_button_label.move(255, 74)

        self.leave_button = QPushButton('  Leave  ', self)
        self.leave_button.move(250, 94)
        self.leave_button.clicked.connect(self.handle_leave)

        self.guest_status_label = QLabel("Guest is:", self)
        self.guest_status_label.move(405, 74)

        self.ready_button = QPushButton('Unready', self)
        self.ready_button.move(400, 94)
        self.ready_button.clicked.connect(self.handle_ready)
        self.ready_button.setEnabled(not self.is_master)

        self.start_button.resize(self.leave_button.sizeHint())
        self.ready_button.resize(self.leave_button.sizeHint())

        self.room_status_label = QLabel(self)
        self.room_status_label.move(255, 140)

        # id label
        self.id_label = QLabel(self)
        self.id_label.move(40, 14)

        self.role_label = QLabel(self)
        self.role_label.move(40, 44)

        if self.is_master:
            self.id_label.setText("Your id: " + self.master_name)
            self.role_label.setText("You're creator of this room.")
            self.room_status_label.setText("Waiting for player ...")
        else:
            self.id_label.setText("Your id: " + self.guest_name)
            self.role_label.setText("You're guest of this room.")
            self.room_status_label.setText("Creator id: " + self.master_name)

        self.show()

    def handle_message(self, message):
        print("Received: ", message)
        if message[0] == 'J':
            # join signal
            if self.is_master:
                self.guest_name = message[1:]
                self.room_status_label.setText("Guest id: " + self.guest_name)
                if self.colors.currentText() == 'Black':
                    self.master_stone = 1
                    self.web_socket.send(BLACK_STONE_SIGNAL_MESSAGE)
                else:
                    self.master_stone = 2
                    self.web_socket.send(WHITE_STONE_SIGNAL_MESSAGE)
        else:
            try:
                signal = int(message)
                print("signal", signal)
                if signal < 0:
                    # START_SIGNAL = -1
                    # GUEST_READY_SIGNAL = -2
                    # GUEST_UNREADY_SIGNAL = -3
                    # GUEST_LEAVE_SIGNAL = -4
                    # MASTER_DELETE_SIGNAL = -5
                    # END_SIGNAL = -6

                    if self.is_master:
                        if signal == GUEST_READY_SIGNAL:
                            print("ready")
                            self.ready = True
                            self.start_button.setEnabled(True)
                            self.ready_button.setText("Ready")
                        elif signal == GUEST_UNREADY_SIGNAL:
                            print("unready")
                            self.ready = False
                            self.start_button.setEnabled(False)
                            self.ready_button.setText("Unready")
                        elif signal == GUEST_LEAVE_SIGNAL:
                            self.ready = False
                            self.start_button.setEnabled(self.ready)
                            self.ready_button.setText("Unready")
                            self.guest_name = None
                            self.room_status_label.setText(
                                "Waiting for player ...")
                        elif signal == START_SIGNAL:
                            print("try to start")
                            self.start_game_signal.emit()
                        else:
                            print("Unvalid master control signal.")
                    else:
                        if signal == START_SIGNAL:
                            print("try to start")
                            self.start_game_signal.emit()
                        elif signal == MASTER_DELETE_SIGNAL:
                            self.hall_hook()
                            self.close()
                            # TODO: pop a message box
                        elif signal == BLACK_STONE_SIGNAL:
                            self.master_stone = 1
                            self.colors.setCurrentIndex(
                                self.colors.findText('Black'))
                        elif signal == WHITE_STONE_SIGNAL:
                            self.master_stone = 2
                            self.colors.setCurrentIndex(
                                self.colors.findText('White'))
                        else:
                            print("Unvalid guest control signal.")
                    # control signal
                else:
                    # should not be processed now
                    print("Moving signal, game does not start yet.")
            except:
                print("Unvalid message format.")

    @pyqtSlot()
    def start_game(self):
        # return to hall after the match
        # if return to room, must init socket, reset the to_influence by calling hook()
        #hall_hook = self.hall_hook

        self.game_board = Gomoku(self.is_master, self.room_name,\
                                self.master_name, self.guest_name,\
                                self.master_stone, self.server_ip,\
                                self.web_socket, self.hall_hook)
        self.game_board.show()
        self.close()

    def init_socket(self):
        # uri = 'ws://' + self.server_ip + ':8080/playing'
        # role can be: "m" for master, "g" for guest, "a" for audience
        # if master use balck stone, "master_stone:1", if white, "master_stone:2"

        # if self.colors.currentText() == 'Black':
        #     master_stone = '1'
        # else:
        #     master_stone = '2'

        self.uri = 'ws://' + self.server_ip + ':8080/playing'
        # self.uri = 'ws://' + self.server_ip + ':8080/test'

        if self.is_master:
            role = 'm'
            user_name = self.master_name
        else:
            role = 'g'
            user_name = self.guest_name

        self.headers = [("role", role),\
            ("roomName", self.room_name),\
            ("userName", user_name),\
            ("masterStone", self.master_stone)]
        self.web_socket = SocketCli(self.uri, headers=self.headers)
        self.web_socket.connect()
        self.web_socket.hook(self)

        if not self.is_master:
            print("before send join")
            self.web_socket.send('J' + self.guest_name)
            print("sent join")

    @pyqtSlot()
    def handle_color_change(self):
        if self.colors.currentText() == 'Black':
            self.master_stone = 1
            print("send: change to balck")
            self.web_socket.send(BLACK_STONE_SIGNAL_MESSAGE)
        else:
            self.master_stone = 2
            print("send: change to white")
            self.web_socket.send(WHITE_STONE_SIGNAL_MESSAGE)

    @pyqtSlot()
    def handle_start(self):
        # donot need to send info to redis,
        # done by server

        self.web_socket.send(START_SIGNAL_MESSAGE)

    @pyqtSlot()
    def handle_leave(self):
        # donot need to send info to redis,
        # done by server

        if self.is_master:
            response = requests.get('http://' + self.server_ip +\
                ':8080/room/delete/'+ self.room_name + '/' +\
                self.master_name, headers=self.auth_headers)
            # if response.text == 'Success':
            #     self.web_socket.send(MASTER_DELETE_SIGNAL_MESSAGE)
            #     self.hall_hook()
            #     self.close()
            # elif response.text == "Unauthorized or timeout.":
            #     pop_info_and_back(self, response.text, self.login_hook)
            # else:
            print('#### Info: master delete: ' + response.text)
            if response.text == 'Success':
                print("Success")
                self.web_socket.send(MASTER_DELETE_SIGNAL_MESSAGE)
                self.web_socket.close()
                self.hall_hook()
            else:
                print("Fail")
                self.web_socket.close()
                self.hall_hook(refresh=True)
            self.close()
        else:
            response = requests.get('http://' + self.server_ip +\
                ':8080/room/leave/'+ self.room_name + '/' +\
                self.guest_name, headers=self.auth_headers)
            # if response.text == 'Success':
            #     self.web_socket.send(GUEST_LEAVE_SIGNAL_MESSAGE)
            #     self.hall_hook()
            #     self.close()
            # elif response.text == "Unauthorized or timeout.":
            #     pop_info_and_back(self, response.text, self.login_hook)
            # else:
            #     print(response.text)
            print('#### Info: guest leave: ' + response.text)
            self.web_socket.send(GUEST_LEAVE_SIGNAL_MESSAGE)
            self.web_socket.close()
            self.hall_hook()
            self.close()
            if response.text == 'Success':
                print("Success")
                self.web_socket.close()
                self.hall_hook()
            else:
                print("Fail")
                self.web_socket.close()
                self.hall_hook(refresh=True)
            self.close()

    @pyqtSlot()
    def handle_ready(self):
        # donot need to send info to redis,
        # done by server

        if self.ready:
            self.ready = False
            self.web_socket.send(GUEST_UNREADY_SIGNAL_MESSAGE)
            self.ready_button.setText("Unready")
        else:
            self.ready = True
            self.web_socket.send(GUEST_READY_SIGNAL_MESSAGE)
            self.ready_button.setText("Ready")
Exemple #6
0
class GomokuWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.init_ui()  # 初始化游戏界面
        self.g = Gomoku()  # 初始化游戏内容

        self.last_pos = (-1, -1)
        self.res = 0  # 记录那边获得了胜利
        self.operate_status = 0  # 游戏操作状态。0为游戏中(可操作),1为游戏结束闪烁过程中(不可操作)

    def init_ui(self):
        """初始化游戏界面"""
        # 1. 确定游戏界面的标题,大小和背景颜色
        self.setObjectName('MainWindow')
        self.setWindowTitle('五子棋')
        self.setFixedSize(650, 650)

        palette = QPalette()
        palette.setBrush(QPalette.Window, QBrush(QPixmap('imgs/muzm.jpg'))) # 把背景替换成木质桌面
        self.setPalette(palette)
        # 2. 开启鼠标位置的追踪。并在鼠标位置移动时,使用特殊符号标记当前的位置
        self.setMouseTracking(True)
        # 3. 鼠标位置移动时,对鼠标位置的特殊标记
        self.corner_widget = CornerWidget(self)
        self.corner_widget.repaint()
        self.corner_widget.hide()
        # 4. 游戏结束时闪烁的定时器
        self.end_timer = QTimer(self)
        self.end_timer.timeout.connect(self.end_flash)
        self.flash_cnt = 0  # 游戏结束之前闪烁了多少次
        self.flash_pieces = ((-1, -1), )  # 哪些棋子需要闪烁
        # 5. 显示初始化的游戏界面
        self.show()

    @run_with_exc
    def paintEvent(self, e):
        """绘制游戏内容"""

        def draw_map():
            """绘制棋盘"""
            qp.setPen(QPen(QColor(0, 0, 0), 2, Qt.SolidLine))  # 棋盘的颜色为黑色
            # 绘制横线
            for x in range(15):
                qp.drawLine(40 * (x + 1), 40, 40 * (x + 1), 600)
            # 绘制竖线
            for y in range(15):
                qp.drawLine(40, 40 * (y + 1), 600, 40 * (y + 1))
            # 绘制棋盘中的星位(黑色圆点)
            qp.setBrush(QColor(0, 0, 0))
            key_points = [(4, 4), (12, 4), (4, 12), (12, 12), (8, 8)]
            for t in key_points:
                qp.drawEllipse(QPoint(40 * t[0], 40 * t[1]), 5, 5)

        def draw_pieces():
            """绘制棋子"""
            # 绘制黑棋子
            qp.setPen(QPen(QColor(0, 0, 0), 1, Qt.SolidLine))
            # qp.setBrush(QColor(0, 0, 0))
            for x in range(15):
                for y in range(15):
                    if self.g.g_map[x][y] == 1:
                        if self.flash_cnt % 2 == 1 and (x, y) in self.flash_pieces:
                            continue
                        radial = QRadialGradient(40 * (x + 1), 40 * (y + 1), 15, 40 * x + 35, 40 * y + 35)  # 棋子的渐变效果
                        radial.setColorAt(0, QColor(96, 96, 96))
                        radial.setColorAt(1, QColor(0, 0, 0))
                        qp.setBrush(QBrush(radial))
                        qp.drawEllipse(QPoint(40 * (x + 1), 40 * (y + 1)), 15, 15)
            # 绘制白棋子
            qp.setPen(QPen(QColor(160, 160, 160), 1, Qt.SolidLine))
            # qp.setBrush(QColor(255, 255, 255))
            for x in range(15):
                for y in range(15):
                    if self.g.g_map[x][y] == 2:
                        if self.flash_cnt % 2 == 1 and (x, y) in self.flash_pieces:
                            continue
                        radial = QRadialGradient(40 * (x + 1), 40 * (y + 1), 15, 40 * x + 35, 40 * y + 35)  # 棋子的渐变效果
                        radial.setColorAt(0, QColor(255, 255, 255))
                        radial.setColorAt(1, QColor(160, 160, 160))
                        qp.setBrush(QBrush(radial))
                        qp.drawEllipse(QPoint(40 * (x + 1), 40 * (y + 1)), 15, 15)

        if hasattr(self, 'g'):  # 游戏还没开始的话,就不用画了
            qp = QPainter()
            qp.begin(self)
            draw_map()  # 绘制棋盘
            draw_pieces()  # 绘制棋子
            qp.end()

    @run_with_exc
    def mouseMoveEvent(self, e):
        # 1. 首先判断鼠标位置对应棋盘中的哪一个格子
        mouse_x = e.windowPos().x()
        mouse_y = e.windowPos().y()
        if 25 <= mouse_x <= 615 and 25 <= mouse_y <= 615 and (mouse_x % 40 <= 15 or mouse_x % 40 >= 25) and (mouse_y % 40 <= 15 or mouse_y % 40 >= 25):
            game_x = int((mouse_x + 15) // 40) - 1
            game_y = int((mouse_y + 15) // 40) - 1
        else:  # 鼠标当前的位置不对应任何一个游戏格子,将其标记为(01, 01
            game_x = -1
            game_y = -1

        # 2. 然后判断鼠标位置较前一时刻是否发生了变化
        pos_change = False  # 标记鼠标位置是否发生了变化
        if game_x != self.last_pos[0] or game_y != self.last_pos[1]:
            pos_change = True
        self.last_pos = (game_x, game_y)
        # 3. 最后根据鼠标位置的变化,绘制特殊标记
        if pos_change and game_x != -1:
            self.setCursor(Qt.PointingHandCursor)
        if pos_change and game_x == -1:
            self.setCursor(Qt.ArrowCursor)
        if pos_change and game_x != -1:
            self.corner_widget.move(25 + game_x * 40, 25 + game_y * 40)
            self.corner_widget.show()
        if pos_change and game_x == -1:
            self.corner_widget.hide()

    @run_with_exc
    def mousePressEvent(self, e):
        """根据鼠标的动作,确定落子位置"""
        if not (hasattr(self, 'operate_status') and self.operate_status == 0):
            return
        if e.button() == Qt.LeftButton:
            # 1. 首先判断按下了哪个格子
            mouse_x = e.windowPos().x()
            mouse_y = e.windowPos().y()
            if (mouse_x % 40 <= 15 or mouse_x % 40 >= 25) and (mouse_y % 40 <= 15 or mouse_y % 40 >= 25):
                game_x = int((mouse_x + 15) // 40) - 1
                game_y = int((mouse_y + 15) // 40) - 1
            else:  # 鼠标点击的位置不正确
                return
            self.g.move_1step(True, game_x, game_y)

            # 2. 根据操作结果进行一轮游戏循环
            res, self.flash_pieces = self.g.game_result(show=True)  # 判断游戏结果
            if res != 0:  # 如果游戏结果为“已经结束”,则显示游戏内容,并退出主循环
                self.repaint(0, 0, 650, 650)
                self.game_restart(res)
                return
            # self.g.ai_move_1step()  # 电脑下一步
            self.g.ai_play_1step()  # 电脑下一步
            res, self.flash_pieces = self.g.game_result(show=True)
            if res != 0:
                self.repaint(0, 0, 650, 650)
                self.game_restart(res)
                return
            self.repaint(0, 0, 650, 650)  # 在游戏还没有结束的情况下,显示游戏内容,并继续下一轮循环

    @run_with_exc
    def end_flash(self):
        # 游戏结束时的闪烁操作
        if self.flash_cnt <= 5:
            # 执行闪烁
            self.flash_cnt += 1
            self.repaint()
        else:
            # 闪烁完毕,执行重新开始的操作
            self.end_timer.stop()
            # 1. 显示游戏结束的信息
            if self.res == 1:
                QMessageBox.about(self, '游戏结束', '玩家获胜!')
            elif self.res == 2:
                QMessageBox.about(self, '游戏结束', '电脑获胜!')
            elif self.res == 3:
                QMessageBox.about(self, '游戏结束', '平局!')
            else:
                raise ValueError('当前游戏结束的标志位为' + self.res + '. 而游戏结束的标志位必须为1, 2 或 3')
            # 2. 游戏重新开始的操作
            self.res = 0
            self.operate_status = 0
            self.flash_cnt = 0
            self.g = Gomoku()  # 重新初始化游戏内容
            self.repaint(0, 0, 650, 650)  # 重新绘制游戏界面

    def game_restart(self, res):
        """游戏出现开始"""
        self.res = res  # 标记谁获胜了
        self.operate_status = 1  # 游戏结束时的闪烁过程中,不可操作
        self.end_timer.start(300)  # 开始结束时闪烁的计时器
Exemple #7
0
def main():
    g = Gomoku()
    g.play()
Exemple #8
0
class GameHallWindow(QWidget):
    """Game hall window, create/ join/ watch a match"""

    def __init__(self, username, server_ip, auth_headers, login_hook, manual_hook):
        super().__init__()
        self.auth_headers = auth_headers
        self.login_hook = login_hook
        self.manual_hook = manual_hook

        self.server_ip = server_ip
        self.username = username

        self.current_page = -1

        self.title = "Game Hall"
        self.top = 100
        self.left = 100
        self.width = 700
        self.height = 500

        self.init_ui()

        self.refresh()

    def init_ui(self):
        """
        init the ui of game hall:
        table, buttons.
        And set the style of them
        """
        self.setWindowTitle(self.title)
        self.setWindowIcon(QIcon('chessboard/gomoku_icon.png')) # set window icon
        self.setGeometry(self.top, self.left, self.width, self.height)

        self.create_room_button = QPushButton('Create', self)
        self.create_room_button.move(580, 20)
        self.create_room_button.clicked.connect(self.handle_create_room)

        self.action_button = QPushButton('Action', self)
        self.action_button.move(580, 70)
        self.action_button.clicked.connect(self.handle_action)
        # disable the action button at first
        self.action_button.setEnabled(False)

        self.refresh_button = QPushButton('Refresh', self)
        self.refresh_button.move(580, 120)
        self.refresh_button.clicked.connect(self.refresh)

        self.back_button = QPushButton('Back', self)
        self.back_button.move(580, 340)
        self.back_button.clicked.connect(self.handle_back)

        self.exit_button = QPushButton('Exit', self)
        self.exit_button.move(580, 390)
        self.exit_button.clicked.connect(self.handle_exit)

        # room list, using table
        self.rooms_observed = QTableWidget(self)
        self.rooms_observed.setRowCount(10)
        self.rooms_observed.setColumnCount(2)
        # change the action button after selecting a room
        self.rooms_observed.clicked.connect(self.handle_click_room_observed)
        # set column name
        self.rooms_observed.setHorizontalHeaderLabels(['Room Name', 'Status'])
        self.rooms_observed.setGeometry(50, 20, 500, 400)

        # cannot edit
        self.rooms_observed.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # choose whole row
        self.rooms_observed.setSelectionBehavior(QAbstractItemView.SelectRows)
        # at most select one row
        self.rooms_observed.setSelectionMode(QAbstractItemView.SingleSelection)
        # hide vertical header
        self.rooms_observed.verticalHeader().setVisible(False)
        # fix the table width
        self.rooms_observed.setColumnWidth(0, 400)
        self.rooms_observed.setColumnWidth(1, 99)
        # disable the scrol bar
        self.rooms_observed.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.rooms_observed.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # disable resizing table
        self.rooms_observed.setCornerButtonEnabled(False)
        self.rooms_observed.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)

        self.create_room_button.resize(self.refresh_button.sizeHint())
        self.action_button.resize(self.refresh_button.sizeHint())
        self.exit_button.resize(self.refresh_button.sizeHint())
        self.back_button.resize(self.refresh_button.sizeHint())

        self.show()

    @pyqtSlot()
    def refresh(self):
        """handle clicking refresh button, refresh the room info in the table"""
        response = requests.get('http://%s:8080/room/all'\
            % self.server_ip,\
            headers=self.auth_headers)
        try:
            self.room_list = response.json()
            print(self.room_list)

            self.max_page = int(len(self.room_list) / 10)
            self.current_page = -1
            self.browse(0)

            # refresh chane the room list, should init the action btn
            self.action_button.setEnabled(False)
            self.action_button.setText("Action")
        except:
            pop_info_and_back(self, response.text, self.login_hook)

            # info = response.text
            # button = QMessageBox.question(self, "Info",\
            #                           info,\
            #                           QMessageBox.Ok,\
            #                           QMessageBox.Ok)
            # if button == QMessageBox.Ok:
            #     self.login_hook()
            #     self.close()
            # else:
            #     self.close()
            #     raise SystemExit(0)

    def browse(self, page):
        """choose the page of rooms to browse"""
        if self.current_page != page:
            self.rooms_observed.clearContents()
            self.current_page = page
            for i in range(10):
                if self.current_page*10+i >= len(self.room_list):
                    break
                self.add_line(self.room_list[self.current_page*10 + i], i)

    def add_line(self, a_room, row_num):
        """add a room into the table, call by browse"""
        self.rooms_observed.setItem(row_num, 0, QTableWidgetItem(a_room['roomName']))
        self.rooms_observed.setItem(row_num, 1, QTableWidgetItem(a_room['roomStatus']))

    @pyqtSlot()
    def handle_create_room(self):
        """create a room, call create window"""
        self.create_room_page = CreateRoomWindow(master_name=self.username,\
            server_ip=self.server_ip,\
            hall_hook=self.hall_hook,\
            login_hook=self.login_hook,\
            auth_headers=self.auth_headers)

        self.create_room_page.show()
        self.close()

    @pyqtSlot()
    def handle_action(self):
        """watch or join or disable based on the room chosen"""
        # selected_row = self.rooms_observed.currentRow()
        action = self.action_button.text()
        print(action)
        if action == "Join":
            self.join_room()
        elif action == "Watch":
            # try to watch the game
            self.watch_game()

    def watch_game(self):
        """call by action_btn, watch a match in certain room"""
        selected_row = self.rooms_observed.currentRow()
        master_name = self.room_list[selected_row + self.current_page * 10]["master"]
        guest_name = self.room_list[selected_row + self.current_page * 10]["guest"]
        room_name = self.rooms_observed.item(selected_row, 0).text()

        uri = 'ws://' + self.server_ip + ':8080/playing'

        socket_headers = [("role", 'a'),\
            ("roomName", room_name),\
            ("userName", self.username),\
            ("masterStone", 1)]

        self.web_socket = SocketCli(uri, headers=socket_headers)
        # self.web_socket.hook(self)

        self.game_board = Gomoku(True, room_name, master_name,\
            guest_name, 1, self.server_ip, self.web_socket,\
            self.hall_hook, True)
        self.game_board.show()
        self.close()

    @pyqtSlot()
    def handle_exit(self):
        """exit the programm, pop a window to ensure"""
        reply = QMessageBox.question(self, 'Exit', 'You sure to exit?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            # TODO: other actions
            self.close()

    @pyqtSlot()
    def handle_back(self):
        self.manual_hook()
        self.close()

    @pyqtSlot()
    def handle_click_room_observed(self):
        """
        select a room in the table,
        change the action_btn based on the game status
        """
        selected_row = self.rooms_observed.currentRow()
        try:
            select_status = self.rooms_observed.item(selected_row, 1).text()
            self.action_button.setEnabled(True)
            if select_status == 'Open':
                self.action_button.setText("Join")
            elif select_status == 'Playing':
                self.action_button.setText("Watch")
            else:
                self.action_button.setEnabled(False)
                self.action_button.setText("Action")
        except:
            self.action_button.setEnabled(False)
            self.action_button.setText("Action")

    def join_room(self):
        """join the room as a guest"""
        selected_row = self.rooms_observed.currentRow()
        try:
            room_name = self.rooms_observed.item(selected_row, 0).text()

            uri = "http://%s:8080/room/join/%s/%s"\
                % (self.server_ip, room_name, self.username)

            result = requests.get(uri, headers=self.auth_headers)

            print('from server: '+ result.text)

            if result.text == "Success":
                master_name = self.room_list[selected_row + self.current_page * 10]["master"]
                self.game_room = GameRoomWindow(room_name, master_name,\
                    self.username, self.server_ip, False, self.hall_hook,\
                    self.login_hook, self.auth_headers)
                self.game_room.show()
                self.close()
            else:
                QMessageBox.warning(self, 'Error', result.text)
        except Exception as e:
            print(e)
            QMessageBox.warning(self, 'Error', "Try again.")

    def hall_hook(self, refresh=True):
        self.show()
        if refresh:
            self.refresh()