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")
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()