def __init__(self, name, sock, parent=None): super().__init__(parent) self.name = name # 对方的昵称 self.setWindowTitle('与 {} 对战中'.format(name)) self.label_statu = QLabel("游戏状态:", self) self.label_statu.resize(100, 20) self.label_statuvalue = QLabel("点击开始", self) self.label_statuvalue.resize(200, 30) self.label_statuvalue.setAlignment(Qt.AlignTop) self.label_statu.move(630, 200) self.label_statuvalue.move(690, 204) # 清空棋盘 global chessboard chessboard = [[None for i in range(0, 19)] for i in range(0, 19)] # 默认情况下游戏是结束状态, 通过开始按钮才可以触发 self.is_over = True # 标识黑旗白旗 self.color = 'w' # 是否是我的回合 self.my_turn = False # 保持连接 self.keep_connect = True # 三个按钮点击触发的函数 self.restart_button.click_signal.connect(self.restart) self.huiqi_button.click_signal.connect(self.goback) self.renshu_button.click_signal.connect(self.lose) self.win_label = None self.cuicu_button = TDPushButton(self, "source/催促按钮_normal.png", "source/催促按钮_hover.png", "source/催促按钮_press.png", parent=self) self.cuicu_button.move(640, 450) self.cuicu_button.click_signal.connect(self.cuicu) self.chess_pos.hide() # 这个位置标识隐藏起来 # 网络模块启动 self.is_connected = True # 默认情况下有连接 self.is_listening = True # 默认情况下启动了监听 self.tcp_socket = sock self.label_statuvalue.setText("连接成功,\n点击开始") threading.Thread(target=self.recv_data, args=(self.tcp_socket, '')).start() self.dataSignal.connect(self.deal_data) self.disconnectSignal.connect(self.dis_connect)
def __init__(self, name, parent=None): super().__init__(parent) self.ip = None self.name = name self.label_statu = QLabel("游戏状态:", self) self.label_statu.resize(100, 20) self.label_statuvalue = QLabel("等待连接", self) self.label_statuvalue.resize(200, 30) self.label_statuvalue.setAlignment(Qt.AlignTop) self.label_statu.move(630, 200) self.label_statuvalue.move(690, 204) # 清空棋盘 global chessboard chessboard = [[None for i in range(0, 19)] for i in range(0, 19)] # 默认情况下游戏是结束状态, 通过开始按钮才可以触发 self.is_over = True # 标识黑旗白旗 self.color = 'w' # 是否是我的回合 self.my_turn = False # 三个按钮点击触发的函数 self.restart_button.click_signal.connect(self.restart) self.huiqi_button.click_signal.connect(self.goback) self.renshu_button.click_signal.connect(self.lose) self.win_label = None self.cuicu_button = TDPushButton(self, "source/催促按钮_normal.png", "source/催促按钮_hover.png", "source/催促按钮_press.png", parent=self) self.cuicu_button.move(640, 450) self.cuicu_button.click_signal.connect(self.cuicu) self.chess_pos.hide() # 这个位置标识隐藏起来 # 网络模块启动 self.is_connected = False # 默认情况下没有连接 self.is_listening = False # 默认情况下没有监听 self.tcp_socket = None # 默认情况下网络连接为None self.dataSignal.connect(self.deal_data)
def initUI(self): self.setFixedSize(760, 650) # 设置固定大小 self.move(200, 10) self.setWindowTitle('五子棋-三级狗') self.setWindowIcon(QIcon('source/icon.ico')) # 设置背景图片 palette1 = QPalette() palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('source/游戏界面.png'))) # 设置背景图片 self.setPalette(palette1) self.back_button = TDPushButton(self, 'source/返回按钮_normal.png', 'source/返回按钮_hover.png', 'source/返回按钮_press.png', parent=self) self.back_button.click_signal.connect(self.back) self.back_button.move(680, 10) self.restart_button = TDPushButton(self, 'source/开始按钮_normal.png', 'source/开始按钮_hover.png', 'source/开始按钮_press.png', parent=self) self.restart_button.move(640, 240) self.huiqi_button = TDPushButton(self, 'source/悔棋按钮_normal.png', 'source/悔棋按钮_hover.png', 'source/悔棋按钮_press.png', parent=self) self.huiqi_button.move(640, 310) self.renshu_button = TDPushButton(self, 'source/认输按钮_normal.png', 'source/认输按钮_hover.png', 'source/认输按钮_press.png', parent=self) self.renshu_button.move(640, 380) # 落棋标志 self.chess_pos = QLabel(self) pic = QPixmap("source/标识.png") self.chess_pos.setPixmap(pic) self.chess_pos.setFixedSize(pic.size()) self.chess_pos.show()
def initUI(self): self.setFixedSize(760, 650)# 设置固定大小 self.move(200, 10) self.setWindowTitle('五子棋-三级狗') self.setWindowIcon(QIcon('source/icon.ico')) # 设置背景图片 palette1 = QPalette() palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('source/五子棋界面.png'))) # 设置背景图片 self.setPalette(palette1) # 加载选择按钮 self.single_button = TDPushButton(self,'source/人机对战_normal.png','source/人机对战_hover.png','source/人机对战_press.png',parent=self) self.single_button.move(250,300) self.single_button.show() self.single_button.click_signal.connect(self.single_player) # 连接信号和槽,点击按钮触发函数 self.double_button = TDPushButton(self,'source/双人对战_normal.png','source/双人对战_hover.png','source/双人对战_press.png',parent=self) self.double_button.move(250,400) self.double_button.show() self.double_button.click_signal.connect(self.double_player) self.network_button = TDPushButton(self,'source/联机对战_normal.png','source/联机对战_hover.png','source/联机对战_press.png',parent=self) self.network_button.move(250,500) self.network_button.show() self.network_button.click_signal.connect(self.network_player) self.game_window = None
class MainWindow(QWidget): def __init__(self, parent=None): super().__init__(parent) self.initUI() # 初始化界面 def initUI(self): self.setFixedSize(760, 650) # 设置固定大小 self.move(200, 10) self.setWindowTitle('五子棋-三级狗') self.setWindowIcon(QIcon('source/icon.ico')) # 设置背景图片 palette1 = QPalette() palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('source/五子棋界面.png'))) # 设置背景图片 self.setPalette(palette1) # 加载选择按钮 self.single_button = TDPushButton(self, 'source/人机对战_normal.png', 'source/人机对战_hover.png', 'source/人机对战_press.png', parent=self) self.single_button.move(250, 300) self.single_button.show() self.single_button.click_signal.connect( self.single_player) # 连接信号和槽,点击按钮触发函数 self.double_button = TDPushButton(self, 'source/双人对战_normal.png', 'source/双人对战_hover.png', 'source/双人对战_press.png', parent=self) self.double_button.move(250, 400) self.double_button.show() self.double_button.click_signal.connect(self.double_player) self.network_button = TDPushButton(self, 'source/联机对战_normal.png', 'source/联机对战_hover.png', 'source/联机对战_press.png', parent=self) self.network_button.move(250, 500) self.network_button.show() self.network_button.click_signal.connect(self.network_player) self.game_window = None def single_player(self): self.close() self.game_window = SinglePlayer() self.game_window.exitSignal.connect(self.game_over) # 游戏结束 self.game_window.backSignal.connect(self.show) # 游戏 self.game_window.show() def double_player(self): self.close() self.game_window = DoublePlayer() self.game_window.exitSignal.connect(self.game_over) # 游戏结束 self.game_window.backSignal.connect(self.show) # 游戏 self.game_window.show() def network_player(self): self.close() self.game_window = NetworkConfig(main_window=self) self.game_window.show() def game_over(self): sys.exit(app.exec_())
class NetworkPlayer(BasePlayer): dataSignal = pyqtSignal(dict, name='data') # 网络对战窗体 def __init__(self, name, parent=None): super().__init__(parent) self.ip = None self.name = name self.label_statu = QLabel("游戏状态:", self) self.label_statu.resize(100, 20) self.label_statuvalue = QLabel("等待连接", self) self.label_statuvalue.resize(200, 30) self.label_statuvalue.setAlignment(Qt.AlignTop) self.label_statu.move(630, 200) self.label_statuvalue.move(690, 204) # 清空棋盘 global chessboard chessboard = [[None for i in range(0, 19)] for i in range(0, 19)] # 默认情况下游戏是结束状态, 通过开始按钮才可以触发 self.is_over = True # 标识黑旗白旗 self.color = 'w' # 是否是我的回合 self.my_turn = False # 三个按钮点击触发的函数 self.restart_button.click_signal.connect(self.restart) self.huiqi_button.click_signal.connect(self.goback) self.renshu_button.click_signal.connect(self.lose) self.win_label = None self.cuicu_button = TDPushButton(self, "source/催促按钮_normal.png", "source/催促按钮_hover.png", "source/催促按钮_press.png", parent=self) self.cuicu_button.move(640, 450) self.cuicu_button.click_signal.connect(self.cuicu) self.chess_pos.hide() # 这个位置标识隐藏起来 # 网络模块启动 self.is_connected = False # 默认情况下没有连接 self.is_listening = False # 默认情况下没有监听 self.tcp_socket = None # 默认情况下网络连接为None self.dataSignal.connect(self.deal_data) def deal_data(self, data): ''' 对收到的数据进行处理 ''' print(data) if data['msg'] == 'action': if data['data'] == 'restart': result = QMessageBox.information( self, "消息", "对方请求(重新)开始游戏,是否同意?", QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: data = {"msg": "replay", "data": True, "type": "restart"} self.tcp_socket.sendall( (json.dumps(data) + " END").encode()) self.restart_func() self.is_over = False if self.my_turn: self.label_statuvalue.setText("己方回合") else: self.label_statuvalue.setText("对方回合") else: data = {"msg": "replay", "data": False, "type": "restart"} self.tcp_socket.sendall( (json.dumps(data) + " END").encode()) self.label_statuvalue.setText("点击开始") if data['data'] == 'lose': QMessageBox.information(self, "消息", "对方认输") if self.my_turn: self.win(color=self.color) # self.change_color() else: self.change_color() self.win(color=self.color) if data['data'] == 'goback': result = QMessageBox.information( self, "消息", "对方请求悔棋,是否同意?", QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: data = {"msg": "replay", "data": True, "type": "goback"} self.tcp_socket.sendall( (json.dumps(data) + " END").encode()) self.goback_func() # self.is_over = False if self.my_turn: self.label_statuvalue.setText("己方回合") else: self.label_statuvalue.setText("对方回合") else: data = {"msg": "replay", "data": False, "type": "goback"} self.tcp_socket.sendall( (json.dumps(data) + " END").encode()) # self.label_statuvalue.setText("等待开始") if data['data'] == 'cuicu': print(self.is_connected) if not self.is_connected: return if self.is_over: return print("cuicu") sound.play() # pygame.mixer.music.load("source/luozisheng.wav") if data['data'] == 'ready': pass if data['data'] == 'exit': # 对方退出游戏 self.is_connected = False self.is_listening = False self.tcp_socket.close() self.tcp_socket = None print(data) elif data['msg'] == 'position': print(data['data']) # 在对应位置落子 pos = data['data'] if chessboard[pos[1]][pos[0]] is not None: return # 如果对应位置不为空,说明有棋子,则直接返回 self.chess = Chessman(self.color, self) self.chess.move(QPoint(pos[0] * 30 + 50, pos[1] * 30 + 50)) self.chess.show() pygame.mixer.music.play() # 播放声音 self.logo_move() # 移动小标 self.change_color() # 在棋盘的对应位置放上棋子 chessboard[pos[1]][pos[0]] = self.chess # 并且在列表中记录坐标 history.append((pos[1], pos[0], self.chess.color)) # 每次落子后,都判断一下胜负 res = is_win(chessboard) if res: self.win(res) # 通过颜色,显示胜利的图片 return self.my_turn = True self.label_statuvalue.setText("己方回合") elif data['msg'] == 'replay': if data['type'] == 'restart': # 重开回执 if data['data'] == True: self.restart_func() else: QMessageBox.information(self, "消息", "对方拒绝了你的请求") self.label_statuvalue.setText("点击开始") return if self.my_turn: self.label_statuvalue.setText("己方回合") else: self.label_statuvalue.setText("对方回合") if data['type'] == 'goback': # 悔棋回执 if data['data'] == True: self.is_over = False self.goback_func() else: QMessageBox.information(self, '消息', '对方拒绝了你的请求') if self.my_turn: self.label_statuvalue.setText("己方回合") else: self.label_statuvalue.setText("对方回合") self.is_over = False elif data['msg'] == 'name': self.setWindowTitle('与 {} 对战中'.format(data['data'])) def restart_func(self): # 清空所有棋子 for j in range(0, 19): for i in range(0, 19): if chessboard[i][j] is not None: chessboard[i][j].close() chessboard[i][j] = None history.clear() # 清空历史数组 if self.is_over: # 如果游戏已经结束 if self.win_label is not None: self.win_label.close() self.win_label = None self.is_over = False self.chess_pos.hide() # 这个位置标识隐藏起来 def recv_data(self, sock, addr): self.is_connected = True # 连接状态 print("start receiving data ...") while True: print("start receiving data ...") try: res_data = recv_sockdata(sock) except (ConnectionAbortedError, ConnectionResetError): print("对方离开游戏") # QMessageBox.information(self,"提示","对方已经断开连接") self.is_connected = False # 连接断开 self.label_statuvalue.setText("对方断线,\n点击开始重试") break try: data = json.loads(res_data, encoding="utf-8") except json.decoder.JSONDecodeError as e: print("error data:\n" + res_data) continue # 在线程处理函数中不能直接进行界面的相关操作,所以用一个信号把数据发送出来 self.dataSignal.emit(data) # self.deal_data(data,parent) self.is_connected = False # 连接断开 self.tcp_socket.close() def closeEvent(self, a0: QCloseEvent): if self.tcp_socket is not None and self.is_connected == True: self.tcp_socket.sendall((json.dumps({ "msg": "action", "data": "exit" })).encode()) self.tcp_socket.close() return super().closeEvent(a0) def win(self, color): ''' 黑旗胜利或者白棋胜利了 ''' if color == 'b': win_pic = QPixmap('source/黑棋胜利.png') self.label_statuvalue.setText("黑旗胜利") else: win_pic = QPixmap('source/白棋胜利.png') self.label_statuvalue.setText("白棋胜利") self.win_label = QLabel(parent=self) self.win_label.setPixmap(win_pic) self.win_label.resize(win_pic.size()) self.win_label.move(50, 50) # 显示游戏结束的图片 self.win_label.show() self.is_over = True # 游戏结束 def mouseReleaseEvent(self, a0: QMouseEvent): if self.is_over: # 如果游戏已经结束,点击失效 return if not self.my_turn: print("not my turn") return # 如果点击在棋盘区域 if a0.x() >= 50 and a0.x() <= 50 + 30 * 19 and a0.y() >= 50 and a0.y( ) <= 50 + 30 * 19: # 讲像素坐标转化成棋盘坐标,判断棋盘此位置是否为空 pos = trans_pos(a0) if chessboard[pos[1]][pos[0]] is not None: return # 如果对应位置不为空,说明有棋子,则直接返回 # 不为空,则生成棋子并显示 self.chess = Chessman(self.color, self) self.chess.move(a0.pos()) self.chess.show() pygame.mixer.music.play() # 播放声音 self.logo_move() # 移动小标 self.change_color() # 在棋盘的对应位置放上棋子 chessboard[pos[1]][pos[0]] = self.chess # 并且在列表中记录坐标 history.append((pos[1], pos[0], self.chess.color)) # 将坐标发送给另一方 if self.tcp_socket is not None: data = {"msg": "position", "data": pos} self.tcp_socket.sendall((json.dumps(data) + " END").encode()) # 每次落子后,都判断一下胜负 res = is_win(chessboard) if res: self.win(res) # 通过颜色,显示胜利的图片 return self.my_turn = False self.label_statuvalue.setText("对方回合") def change_color(self): if self.color == 'w': self.color = 'b' else: self.color = 'w' def restart(self): ''' 重新开始游戏 ''' pass def goback(self): ''' 悔棋按钮 ''' if self.my_turn is False: return # 如果是对方回合,不能悔棋 if self.is_over: return if not self.is_connected: return else: data = {"msg": "action", "data": "goback"} self.tcp_socket.sendall((json.dumps(data) + " END").encode()) self.label_statuvalue.setText("请求悔棋") self.is_over = True def goback_func(self): if self.is_over: return None # 如果游戏已经结束了 if len(history) == 0: return None # 没有落子,不能悔棋 chess = history.pop(-1) chessboard[chess[0]][chess[1]].close() chessboard[chess[0]][chess[1]] = None # self.change_color() if len(history) == 0: return None # 没有落子,不能悔棋 chess = history.pop(-1) chessboard[chess[0]][chess[1]].close() chessboard[chess[0]][chess[1]] = None # self.change_color() self.chess_pos.hide() # 这个位置标识隐藏起来 def lose(self): ''' 认输按钮 ''' if self.is_over: return if not self.is_connected: return else: data = {"msg": "action", "data": "lose"} self.tcp_socket.sendall((json.dumps(data) + " END").encode()) self.label_statuvalue.setText("对方胜利") if self.my_turn: self.change_color() self.win(color=self.color) else: self.win(color=self.color) def cuicu(self): ''' 催促按钮 ''' if self.my_turn: return if self.is_over: return if not self.is_connected: return else: data = {"msg": "action", "data": "cuicu"} self.tcp_socket.sendall((json.dumps(data) + " END").encode()) # self.label_statuvalue.setText("请求(重新)开始") def logo_move(self): self.chess_pos.show() self.chess_pos.move(self.chess.pos()) self.chess_pos.raise_()
class BasePlayer(QWidget): ''' 游戏对战窗体的基类,单人游戏,双人游戏和网络对战都是继承自这个类,这个类中实现并加载了了所有公共的控件 ''' backSignal = pyqtSignal() # 点击后退按钮触发的信号 exitSignal = pyqtSignal() # 如果程序退出,触发的信号 def __init__(self, parent=None): super().__init__(parent) self.initUI() self.is_exit = True def initUI(self): self.setFixedSize(760, 650) # 设置固定大小 self.move(200, 10) self.setWindowTitle('五子棋-三级狗') self.setWindowIcon(QIcon('source/icon.ico')) # 设置背景图片 palette1 = QPalette() palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('source/游戏界面.png'))) # 设置背景图片 self.setPalette(palette1) self.back_button = TDPushButton(self, 'source/返回按钮_normal.png', 'source/返回按钮_hover.png', 'source/返回按钮_press.png', parent=self) self.back_button.click_signal.connect(self.back) self.back_button.move(680, 10) self.restart_button = TDPushButton(self, 'source/开始按钮_normal.png', 'source/开始按钮_hover.png', 'source/开始按钮_press.png', parent=self) self.restart_button.move(640, 240) self.huiqi_button = TDPushButton(self, 'source/悔棋按钮_normal.png', 'source/悔棋按钮_hover.png', 'source/悔棋按钮_press.png', parent=self) self.huiqi_button.move(640, 310) self.renshu_button = TDPushButton(self, 'source/认输按钮_normal.png', 'source/认输按钮_hover.png', 'source/认输按钮_press.png', parent=self) self.renshu_button.move(640, 380) # 落棋标志 self.chess_pos = QLabel(self) pic = QPixmap("source/标识.png") self.chess_pos.setPixmap(pic) self.chess_pos.setFixedSize(pic.size()) self.chess_pos.show() def closeEvent(self, a0: QCloseEvent): if self.is_exit: # 默认情况下,关闭窗体,退出游戏。如果点击返回按钮,则is_exit被设置为False,不触发此信号。 self.exitSignal.emit() else: self.backSignal.emit() def back(self): self.is_exit = False self.close() def logo_move(self): pass