Python實現人機五子棋

圖片和代碼資源已經上傳到百度雲,鏈接:https://pan.baidu.com/s/1g0OO-8k-GNO9I4ZbFt1AXw

圖形界面引用PyQt5,還有socket通信。可以局域網對戰,可以人機對戰,應該存在一些小的bug,但是還沒有找出來。希望讀者可以找到,哈哈…

下面附幾張運行的截圖:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

五子棋.py代碼:


from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys

import MyButton
import DoublePlayerGame
import SinglePlayerGame
from NetConfig import *
import NetPlayerGame


class Mainwindow(QWidget):

    

    def __init__(self,parent = None):
        super().__init__(parent)
        self.resize(760,650)
        self.setWindowTitle("我的五子棋")
        #設置窗口圖標
        self.setWindowIcon(QIcon("source/icon.ico"))



        #設置背景圖片
        p = QPalette(self.palette())#獲得當前的調色板
        brush = QBrush(QImage("source/五子棋界面.png"))
        p.setBrush(QPalette.Background,brush)#設置調色版
        self.setPalette(p)#給窗口設置調色板


        self.singlePlayerBtn = MyButton.MyButton('source/人機對戰_hover.png',
                     'source/人機對戰_normal.png',
                     'source/人機對戰_press.png',
                     parent=self)
        self.singlePlayerBtn.move(300,300)

        self.dancelePlayerBtn = MyButton.MyButton('source/雙人對戰_hover.png',
                     'source/雙人對戰_normal.png',
                     'source/雙人對戰_press.png',
                     parent=self)
        self.dancelePlayerBtn.move(300,400)
        #self.dancelePlayerBtn.clicked.connect(DoublePlayerGame)

        self.drawlePlayerBtn = MyButton.MyButton('source/聯機對戰_hover.png',
                     'source/聯機對戰_normal.png',
                     'source/聯機對戰_press.png',
                     parent=self)
        self.drawlePlayerBtn.move(300,500)

        #綁定開始雙人遊戲信號和槽函數
        self.dancelePlayerBtn.clicked.connect(self.startDoubliGame)
        self.singlePlayerBtn.clicked.connect(self.startSingleGame)
        self.drawlePlayerBtn.clicked.connect(self.startNetGame)


    def startDoubliGame(self):
        print("in")
        #構建雙人對戰界面
        self.doublePlayerGame = DoublePlayerGame.DoublePlayGame()
        #綁定返回界面
        self.doublePlayerGame.backSignal.connect(self.showStartGame)
        
        self.doublePlayerGame.show()#顯示遊戲界面
        self.close()


    def startSingleGame(self):
        self.SingleGame = SinglePlayerGame.SinglePlayerGame()
        self.SingleGame.backSignal.connect(self.showStartGame2)
        self.SingleGame.show()
        self.close()



    def startNetGame(self):
        self.netConfig = NetConfigWidget()
        self.netConfig.exit_signal.connect(self.show)
        self.netConfig.show()
        self.netConfig.config_signal.connect(self.receiveNetConfig)
        self.close()


    def receiveNetConfig(self,nettype,name,ip,port):
        '''
        接收網絡配置信息
        '''
        print("net config:",nettype,name,ip,port)
        if nettype == "client":
            net_object = NetClient(name,ip,port)
        elif nettype == "server":
            net_object = NetServer(name,ip,port)
        else:
            return
        self.netPlayerGame = NetPlayerGame.NetPlayerGame(net_object=net_object)
        self.netPlayerGame.backSignal.connect(self.show)
        self.close()
        self.netPlayerGame.show()
        self.netConfig.hide()
        '''lbl = QLabel(self)
        pix = QPixmap("source/人機大戰_norma.")'''

    #顯示開始界面
    def showStartGame(self):
        self.show()
        self.doublePlayerGame.close()

    def showStartGame2(self):
        self.show()
        self.SingleGame.close()
    

if __name__ == "__main__":
    import cgitb
    cgitb.enable("text")
    a = QApplication(sys.argv)
    m = Mainwindow()
    m.show()
    sys.exit(a.exec_())

doubleplayergame.py代碼:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import *
import sys


class Chessman(QLabel):

    def __init__(self, color = "black",parent = None):
        super().__init__(parent)
        self.color = color
        self.pic = None
        if self.color == "black":
            self.pic = QPixmap("source/黑子.png")
        else:
            self.pic = QPixmap("source/白子.png")
        self.setPixmap(self.pic)
        self.setFixedSize(self.pic.size())#設置棋子大小
        self.show()

        self.x = 0
        self.y = 0

    def move(self,a0:QtCore.QPoint):
        super().move(a0.x()-15,a0.y()-15)

    def setIndex(self,x,y):
        self.x = x
        self.y = y

import MyButton

class DoublePlayGame(QWidget):
    
    backSignal = pyqtSignal()#返回信號
    def __init__(self,parent = None):
        super().__init__(parent=parent)
        #左上角chessboard[0][0]
        #右上角chessboard[0][18]
        #左下角chessboard[18][0]
        #右下角chessboard[18][18]
        #chessboard[行下標][列下標]
        self.chessboard = [[None for i in range(19)] for i in range(19)]
        #落子棋子顏色
        self.turnChessColor = "black"
        self.history = []
        self.history2 = []
        self.is_over = False

        #配置背景圖
        p = QPalette(self.palette())#獲得當前的調色板
        brush = QBrush(QImage("source/遊戲界面.png"))
        p.setBrush(QPalette.Background,brush)#設置調色版
        self.setPalette(p)#給窗口設置調色板

        #設置標題
        #self.resize(760,650)
        self.setWindowTitle("雙人聯機")

        #設置窗口圖標
        self.setWindowIcon(QIcon("source/icon.ico"))
        #設置窗口大小
        self.setFixedSize(QImage("source/遊戲界面.png").size())

        self.backBtn = MyButton.MyButton('source/返回按鈕_hover.png',
                     'source/返回按鈕_normal.png',
                     'source/返回按鈕_press.png',
                     parent=self)
        self.backBtn.move(650,50)

        self.startBtn = MyButton.MyButton('source/開始按鈕_hover.png',
                     'source/開始按鈕_normal.png',
                     'source/開始按鈕_press.png',
                     parent=self)
        self.startBtn.move(650,300)

        self.returnBtn = MyButton.MyButton('source/悔棋按鈕_hover.png',
                     'source/悔棋按鈕_normal.png',
                     'source/悔棋按鈕_press.png',
                     parent=self)
        self.returnBtn.move(650,400)

        self.loseBtn = MyButton.MyButton('source/認輸按鈕_hover.png',
                     'source/認輸按鈕_normal.png',
                     'source/認輸按鈕_press.png',
                     parent=self)
        self.loseBtn.move(650,500)

        #綁定返回按鈕
        self.backBtn.clicked.connect(self.goBack)
        self.startBtn.clicked.connect(self.restar)
        self.loseBtn.clicked.connect(self.lose)
        self.returnBtn.clicked.connect(self.huiback)

        self.gameStatu = []

        self.focusPoint = QLabel(self)
        self.focusPoint.setPixmap(QPixmap("source/標識.png"))

    def goBack(self):
        self.backSignal.emit()
        self.close()

    def closeEvent(self, a0: QtGui.QCloseEvent):
        self.backSignal.emit()




    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
        if self.gameStatu == False:
            return None
        print(a0.pos())
        print("x:",a0.x())
        print("y:",a0.y())
        pos,chess_index = self.reversePos(a0)
        if pos is None:
            return

        if self.chessboard[chess_index[1]][chess_index[0]] != None:
            return

        
        self.chess = Chessman(color=self.turnChessColor,parent=self)
        self.chess.setIndex(chess_index[0], chess_index[1])
        self.chess.move(pos)
        self.chess.show()#顯示棋子
        self.history.append(self.chess)
        self.history2.append(self.focusPoint)

        self.focusPoint.move(QPoint(pos.x()-15,pos.y()-15))
        self.focusPoint.show()
        self.focusPoint.raise_()

        print("棋盤交點位置:",chess_index)

        #放入棋盤
        self.chessboard[chess_index[1]][chess_index[0]] = self.chess

        if self.turnChessColor=="black":
            self.turnChessColor="white"
        else:
            self.turnChessColor="black"

        self.lbl = None
        result = self.isWin(self.chess)
        if result != None:
            print(result + '贏了')
            self.showResult(result)
            
        #自動落子
        #self.autoDown()
    #座標轉換
    def reversePos(self, a0: QtCore.QPoint):
        if a0.x() <= 50 - 15 or a0.x() >= 590 +15 or a0.y() <= 50 - 15 or a0.y() >= 590+15 :
            return None, None
        self.x = (a0.x()-35)//30
        self.y = (a0.y()-35)//30
        x = 50+30*self.x
        y = 50+30*self.y
        return QPoint(x, y),(self.x, self.y)
        
    def isWin(self,chessman):
        print("in iswin,lastChessman:",chessman.color,chessman.x,chessman.y)
        #水平方向y相同,chessboard[chessman.y][i]
        count = 1
        #左邊
        i = chessman.x - 1
        while i>=0:
            if self.chessboard[chessman.y][i] == None or self.chessboard[chessman.y][i].color != chessman.color:
                break
            count += 1
            i -= 1
        #右邊
        i = chessman.x + 1
        while i<=18:
            if self.chessboard[chessman.y][i] == None or self.chessboard[chessman.y][i].color != chessman.color:
                break
            count += 1
            i += 1

        if count >=5:
            return chessman.color

        count = 1
        j = chessman.y - 1
        while j >= 0:
            if self.chessboard[j][chessman.x] == None or self.chessboard[j][chessman.x].color != chessman.color:
                break
            count += 1
            j -= 1

        j = chessman.y + 1
        while j <= 18:
            if self.chessboard[j][chessman.x] == None or self.chessboard[j][chessman.x].color != chessman.color:
                break
            count += 1
            j += 1



        if count >=5:
            return chessman.color

        count = 1
        j,i = chessman.y - 1,chessman.x + 1
        while j >= 0 and i <= 18:
            if self.chessboard[j][i] == None or self.chessboard[j][i].color != chessman.color:
                break
            count += 1
            j -= 1
            i += 1

        j,i = chessman.y + 1,chessman.x - 1
        while i >= 0 and j <= 18:
            if self.chessboard[j][i] == None or self.chessboard[j][i].color != chessman.color:
                break
            count += 1
            i -= 1
            j += 1
        if count >=5:
            return chessman.color

        count = 1
        j,i = chessman.y-1,chessman.x-1
        while j>=0 and i>=0:
            if self.chessboard[j][i] == None or self.chessboard[j][i].color != chessman.color:
                break
            count += 1
            j -= 1
            i -= 1

        j,i = chessman.y+1,chessman.x+1
        while j<=18 and i<=18:
            if self.chessboard[j][i] == None or self.chessboard[j][i].color != chessman.color:
                break
            count += 1
            j += 1
            i += 1

        if count >=5:
            return chessman.color

        return None



    def showResult(self,isWin = None):
        self.gameStatu = False
        if isWin == "white":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/白棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show()
        elif isWin == "black":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/黑棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show() 
        else:
            return

    def restar(self):
        for i in range(19):
            for j in range(19):
                if self.chessboard[i][j] != None:
                    self.chessboard[i][j].close()
                    self.chessboard[i][j] = None
                    self.focusPoint.close()
                else:
                    pass
        if self.lbl != None:
            self.lbl.close() 

        self.gameStatu = True           

        
        

    def lose(self):
        if self.gameStatu == False:
            return
        if self.turnChessColor == "black":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/白棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show()
        elif self.turnChessColor == "white":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/黑棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show()
        else:
            return

    def huiback(self):
        if self.gameStatu == False:
            return
        m = self.history.pop()
        a = self.history2.pop()
        self.chessboard[m.y][m.x] = None
        m.close()  
        a.close() 
        if self.turnChessColor=="black":
            self.turnChessColor="white"
        else:
            self.turnChessColor="black"
     

if __name__ == "__main__":
    import cgitb
    cgitb.enable("text")
    a = QApplication(sys.argv)
    m = DoublePlayGame()
    m.show()
    sys.exit(a.exec_())
    pass

NetConfig.py代碼:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import *
import socket
import threading
class NetConfigWidget(QWidget):
    config_signal = pyqtSignal([str,str,str,str])
    exit_signal = pyqtSignal()
    def __init__(self,parent = None):
        super().__init__(parent = parent)
        self.initUI()

    def initUI(self):
        self.setWindowTitle("網絡配置")
        self.name_label = QLabel("姓名:",self)
        self.name_input = QLineEdit("玩家1",self)
        self.ip_label = QLabel("IP:",self)
        self.ip_input = QLineEdit("127.0.0.1",self)
        self.port_label = QLabel("Prot:",self)
        self.port_input = QLineEdit("10086",self)
        self.client_button = QPushButton("鏈接主機",self)
        self.server_button = QPushButton("我是主機",self)
        

        gridLayout = QGridLayout()
        gridLayout.addWidget(self.name_label,0,0)
        gridLayout.addWidget(self.name_input,0,1)
        gridLayout.addWidget(self.ip_label,1,0)
        gridLayout.addWidget(self.ip_input,1,1)
        gridLayout.addWidget(self.port_label,2,0)
        gridLayout.addWidget(self.port_input,2,1)
        gridLayout.addWidget(self.client_button,3,0)
        gridLayout.addWidget(self.server_button,3,1)
        self.setLayout(gridLayout)

        self.client_button.clicked.connect(self.client_btn_signal)
        self.server_button.clicked.connect(self.server_btn_signal)

    def server_btn_signal(self):
        self.config_signal.emit("server",self.name_input.text(),self.ip_input.text(),self.port_input.text())
    
    def client_btn_signal(self):
        self.config_signal.emit("client",self.name_input.text(),self.ip_input.text(),self.port_input.text())

    def closeEvent(self,a0:QtGui.QCloseEvent):
        self.close()
        self.exit_signal.emit()

class NetClient(QObject):
    msg_signal = pyqtSignal([str])
    def __init__(self,name,ip,port):
        super().__init__()
        self.name = name
        self.ip = ip
        self.port = port
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    def buildConnect(self):
        '''建立鏈接'''
        self.socket.connect((self.ip,int(self.port)))
        threading.Thread(target=self.recv).start()
        pass

    def send(self,data):
        '''發送數據
        data(發送的數據)字符串類型'''
        self.socket.send(data.encode())
        pass

    def recv(self):
        '''接收數據'''
        while True:
            try:
                data  = self.socket.recv(4096).decode()
                self.msg_signal.emit(data)
            except:
                pass

class NetServer(QObject):
    msg_signal = pyqtSignal([str])
    def __init__(self,name,ip,port):
        super().__init__()
        self.name = name
        self.ip = ip
        self.port = port
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.cli_socket = None

    def buildConnect(self):
        self.socket.bind(("",int(self.port)))
        self.socket.listen(1)
        threading.Thread(target=self.__acceptConnect).start()


    def __acceptConnect(self):
        try:
            self.cli_socket,cli_addr = self.socket.accept()
        except:
            pass
        
        while True:
            try:
                data = self.cli_socket.recv(4096).decode()
                self.msg_signal.emit(data)
            except Exception as e:
                print(e)

    def send(self,data):
        if self.cli_socket == None:
            return
        self.cli_socket.send(data.encode())

        


if __name__ == "__main__":
    import sys
    import cgitb
    cgitb.enable("text")
    a = QApplication(sys.argv)
    m = NetConfigWidget()
    m.show()
    sys.exit(a.exec_())
    pass

NetplayerGame.py代碼:

from DoublePlayerGame import *
import json
from NetConfig import *
from PyQt5.QtMultimedia import QSound

class NetPlayerGame(DoublePlayGame):
    def __init__(self,net_object, parent = None):
        super().__init__(parent = parent)
        self.net_object = net_object
        self.net_object.buildConnect()#建立網絡鏈接
        self.net_object.msg_signal.connect(self.parseData)
        self.m_color = None#玩家棋子顏色

        self.cuicuBtn = MyButton.MyButton('source/催促按鈕_hover.png',
                     'source/催促按鈕_normal.png',
                     'source/催促按鈕_press.png',
                     parent=self)
        self.cuicuBtn.move(650,600)

        self.cuicuBtn.clicked.connect(self.cuicu)

    def cuicu(self):
        QSound.play('source/cuicu.wav')
        msg = {}
        msg['msg_type'] = 'cuicu'
        self.net_object.send(json.dumps(msg))
        pass

    def goBack(self):
        self.backSignal.emit()
        self.close()
        self.net_object.socket.close()


    def downChessman(self,point,color):
        '''
        自動落子
        :return:
        '''
        #point = self.getPoint()

        # 注意:x,y座標對應
        chess_index = (point.y(), point.x())  # 棋子在棋盤中的下標
        pos = QPoint(50+point.x()*30, 50+point.y()*30) # 棋子在棋盤中的座標

        self.chessman = Chessman(color=color, parent=self)
        self.chessman.setIndex(chess_index[0], chess_index[1])
        self.chessman.move(pos)
        self.chessman.show()  # 顯示棋子

        # 顯示標識
        self.focusPoint.move(QPoint(pos.x() - 15, pos.y() - 15))
        self.focusPoint.show()
        self.focusPoint.raise_()

        self.chessboard[chess_index[0]][chess_index[1]] = self.chessman

        # 歷史記錄
        self.history.append((chess_index[0], chess_index[1], self.chessman.color))

        # 改變落子顏色
        if self.turnChessColor == 'black':
            self.turnChessColor = 'white'
        else:
            self.turnChessColor = 'black'
        # 判斷輸贏
        result = self.isWin(self.chessman)
        if result != None:
            print(result + '贏了')
            self.showResult(result)

        pass
    '''
    {
        "msg_type":"positon",
        "x":"10",
        "y":"15",
        "color":"black"
    }
    '''
    #解析網路數據
    def parseData(self,data):
        print("pardata:",data)
        try:
            msg = json.loads(data)
        except Exception as e:
            print(e)
            
        #msg = json.loads(data)
        print("msg:",msg)
        if msg["msg_type"] == "position":
            self.downChessman(QPoint(int(msg["x"]),int(msg["y"])),msg["color"])
            pass

        elif msg["msg_type"] == "restart":
            result = QMessageBox.information(None,'五子棋_提示消息','請求開始遊戲',QMessageBox.Yes |QMessageBox.No)
            if result == QMessageBox.Yes:
                self.restartGame()#白子
                self.m_color = 'white'
                msg = {}
                msg['msg_type'] = "response"
                msg['action_type'] = 'restart'
                msg['action_result'] = 'yes'
                self.net_object.send(json.dumps(msg))

            else:
                msg = {}
                msg['msg_type'] = "response"
                msg['action_type'] = 'restart'
                msg['action_result'] = 'no'
                self.net_object.send(json.dumps(msg))
        elif msg['msg_type'] == 'response':
            if msg['action_type'] == 'restart':
                if msg['action_result'] == 'yes':
                    self.restartGame()
                    self.m_color = 'balck'
                else:
                    QMessageBox.information(self,'五子棋_提示消息','對方拒絕遊戲')
            elif msg['action_type'] == 'huiqi':
                if msg['action_result'] == 'Yes':
                    self.huiqigame()
                else:
                    QMessageBox.information(self,'五子棋_提示消息','對方拒絕悔棋',QMessageBox.Yes |QMessageBox.No)


        elif msg['msg_type'] == 'huiqi':
            result = QMessageBox.information(self,'五子棋_提示消息','對方請求悔棋',QMessageBox.Yes |QMessageBox.No)
            if result == QMessageBox.Yes:  
                msg = {}
                msg['msg_type'] = "response"
                msg['action_type'] = 'huiqi'
                msg['action_result'] = 'Yes'
                self.net_object.send(json.dumps(msg))
                self.huiqigame()
            else:
                msg = {}
                msg['msg_type'] = "response"
                msg['action_type'] = 'huiqi'
                msg['action_result'] = 'No'
                self.net_object.send(json.dumps(msg))
        elif msg['msg_type'] == 'lose':
            show.showResult(self.m_color)

        elif msg['msg_type'] == 'cuicu':
            QSound.play('source/cuicu.wav')
            QMessageBox.window(self,'0')


                



    def restartGame(self):

        for i in range(19):
            for j in range(19):
                if self.chessboard[i][j] != None:
                    self.chessboard[i][j].close()
                    self.chessboard[i][j] = None
                    self.focusPoint.close()
                else:
                    pass
        self.lbl = None
        if self.lbl != None:
            self.lbl.close() 

        self.gameStatu = True 
        self.focusPoint.hide()
        self.turnChessColor="black"
            

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
        if self.m_color != self.turnChessColor:
            return
        if self.gameStatu == False:
            return None
        pos,chess_index = self.reversePos(a0)
        if pos is None:
            return
        if self.chessboard[chess_index[1]][chess_index[0]] != None:
            return

        self.chess = Chessman(color=self.turnChessColor,parent=self)
        self.chess.setIndex(chess_index[1], chess_index[0])
        self.chess.move(pos)
        self.chess.show()#顯示棋子
        self.history.append(self.chess)
        self.history2.append(self.focusPoint)

        self.focusPoint.move(QPoint(pos.x()-15,pos.y()-15))
        self.focusPoint.show()
        self.focusPoint.raise_()

        print("棋盤交點位置:",chess_index)

        #放入棋盤
        self.chessboard[chess_index[1]][chess_index[0]] = self.chess
        #發送落子信息
        msg = {}
        msg["msg_type"] = "position"
        msg["x"] = chess_index[1]
        msg["y"] = chess_index[0]
        msg["color"] = self.turnChessColor
        self.net_object.send(json.dumps(msg))
       

        if self.turnChessColor=="black":
            self.turnChessColor="white"
        else:
            self.turnChessColor="black"
        
        self.lbl = None
        result = self.isWin(self.chess)
        if result != None:
            print(result + '贏了') 
            self.showResult(result)


    def huiqi(self):
        if self.gameStatu == None:
            QMessageBox.warning(self,'五子棋提示','遊戲沒有開始,不能悔棋')
        if self.m_color != self.turnChessColor:
            QMessageBox.warning(self,'五子棋提示','不是你的回合')
        msg = {}
        msg['msg_type'] = 'huiqi'
        self.net_object.send(json.dumps(msg))

    def huiqigame(self):
        if self.gameStatu == False:
            return
        m = self.history.pop()
        a = self.history2.pop()
        self.chessboard[m.y][m.x] = None
        m.close()  
        a.close() 
        if self.turnChessColor=="black":
            self.turnChessColor="white"
        else:
            self.turnChessColor="black"

    def restar(self):
        msg = {}
        msg["msg_type"] = "restart"
        self.net_object.send(json.dumps(msg))



def lose(self):
        if self.gameStatu == False:
            QMessageBox.warning(None,'五子棋','遊戲沒有開始')
        if self.m_color == "black":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/白棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show()
        elif self.m_color == "white":
            self.lbl = QLabel(self)
            self.lbl.setPixmap(QPixmap("source/黑棋勝利.png"))
            self.lbl.move(150,150)
            self.lbl.show()
        else:
            return
        msg = {}
        msg['msg_type'] = "lose"
        #msg['action_type'] = 'restart'
        #msg['action_result'] = 'no'
        self.net_object.send(json.dumps(msg))
        


if __name__ == '__main__':
    import cgitb
    cgitb.enable("text")
    a = QApplication(sys.argv)
    m = NetPlayerGame()
    m.show()
    sys.exit(a.exec_())
    pass

MyButton.py代碼:

# -*- coding:utf-8 -*-
# @author: alex  
# @time: 2018/12/27 16:29
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5 import *
from PyQt5.QtGui import *
import sys

from PyQt5.QtCore import *

class MyButton(QLabel):


    clicked = pyqtSignal()#自定義一個信號

    def __init__(self, *args, parent=None):
        super().__init__(parent)

        self.hoverPixmap = QPixmap(args[0])
        self.normalPixmap = QPixmap(args[1])
        self.pressPixmap = QPixmap(args[2])

        self.enterState = False
        self.setPixmap(self.normalPixmap)
        self.setFixedSize(self.normalPixmap.size())

    def mouseReleaseEvent(self, ev: QtGui.QMouseEvent):
        if self.enterState == False:
            self.setPixmap(self.normalPixmap)
        else:
            self.setPixmap(self.hoverPixmap)

        self.clicked.emit()#發射信號

        print("鼠標釋放")
        pass

    def mousePressEvent(self, ev: QtGui.QMouseEvent):
        self.setPixmap(self.pressPixmap)
        print("鼠標按下")
        pass

    def enterEvent(self, a0: QtCore.QEvent):
        self.setPixmap(self.hoverPixmap)
        self.enterState = True
        print("鼠標進入")
        pass

    def leaveEvent(self, a0: QtCore.QEvent):
        self.setPixmap(self.normalPixmap)
        self.enterState = False
        print("鼠標離開")
        pass


if __name__ == '__main__':
    a = QApplication(sys.argv)
    mybtn = MyButton('source/人機對戰_hover.png',
                     'source/人機對戰_normal.png',
                     'source/人機對戰_press.png')
    mybtn.show()
    sys.exit(a.exec_())

SingerPlayerGame.py代碼:


from DoublePlayerGame import *

class SinglePlayerGame(DoublePlayGame):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setWindowTitle('五子棋-單機模式')

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):

        if self.gameStatu == False:
            return None
        print(a0.pos())
        print("x:",a0.x())
        print("y:",a0.y())
        pos,chess_index = self.reversePos(a0)
        if pos is None:
            return

        if self.chessboard[chess_index[1]][chess_index[0]] != None:
            return
        # 玩家落子
        super().mouseReleaseEvent(a0)
            # 電腦落子
        self.autoDown()

    def getPointScore(self, x, y, color):
        '''
        返回每個點的得分
        y:行座標
        x:列座標
        color:棋子顏色
        :return:
        '''
        # 分別計算點周圍5子以內,空白、和同色的分數
        blank_score = 0
        color_score = 0

        # 記錄每個方向的棋子分數
        blank_score_plus = [0, 0, 0, 0]  # 橫向 縱向 正斜線 反斜線
        color_score_plus = [0, 0, 0, 0]

        # 橫線
        # 右側
        i = x  # 橫座標
        j = y  # 縱座標
        while i < 19:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[0] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[0] += 1
            else:
                break
            if i >= x + 4:
                break
            i += 1
        # print('123123')
        # 左側
        i = x  # 橫座標
        j = y  # 縱座標
        while i >= 0:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[0] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[0] += 1
            else:
                break
            if i <= x - 4:
                break
            i -= 1

        # 豎線
        # 上方
        i = x  # 橫座標
        j = y  # 縱座標
        while j >= 0:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[1] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[1] += 1
            else:
                break
            if j <= y - 4:
                break
            j -= 1
        # 豎線
        # 下方
        i = x  # 橫座標
        j = y  # 縱座標
        while j < 19:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[1] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[1] += 1
            else:
                break

            if j >= y + 4:  # 最近五個點
                break
            j += 1
        # 正斜線
        # 右上
        i = x
        j = y
        while i < 19 and j >= 0:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[2] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[2] += 1
            else:
                break

            if i >= x + 4:  # 最近五個點
                break
            i += 1
            j -= 1
        # 左下
        i = x
        j = y
        while j < 19 and i >= 0:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[2] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[2] += 1
            else:
                break

            if j >= y + 4:  # 最近五個點
                break
            i -= 1
            j += 1
        # 反斜線
        # 左上
        i = x
        j = y
        while i >= 0 and j >= 0:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[3] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[3] += 1
            else:
                break
            if i <= x - 4:
                break
            i -= 1
            j -= 1
        # 右上
        i = x
        j = y
        while i < 19 and j < 19:
            if self.chessboard[j][i] is None:
                blank_score += 1
                blank_score_plus[3] += 1
                break
            elif self.chessboard[j][i].color == color:
                color_score += 1
                color_score_plus[3] += 1
            else:
                break
            if i >= x + 4:
                break
            i += 1
            j += 1

        for k in range(4):
            if color_score_plus[k] >= 5:
                return 100

        # color_score *= 5
        return max([x + y for x, y in zip(color_score_plus, blank_score_plus)])

    def getPoint(self):
        '''
        返回落子位置
        :return:
        '''
        # 簡單實現:返回一個空白交點
        # for i in range(19):
        #     for j in range(19):
        #         if self.chessboard[i][j] == None:
        #             return QPoint(j, i)
        #
        #  沒有找到合適的點
        white_score = [ [ 0 for i in range(19) ] for j in range(19)]
        black_score = [ [ 0 for i in range(19) ] for j in range(19)]

        for i in range(19):
            for j in range(19):
                if self.chessboard[i][j] != None:
                    continue
                # 模擬落子
                self.chessboard[i][j] = Chessman(color='white',parent=self)
                white_score[i][j] = self.getPointScore(j, i, 'white')
                self.chessboard[i][j].close()
                self.chessboard[i][j] = None
                self.chessboard[i][j] = Chessman(color='black',parent=self)
                black_score[i][j] = self.getPointScore(j, i, 'black')
                self.chessboard[i][j].close()
                self.chessboard[i][j] = None


        print('----------------')
        # 將二維座標轉換成以爲進行計算
        r_white_score =  []
        r_black_score = []
        for i in white_score:
            r_white_score.extend(i)
        for i in black_score:
            r_black_score.extend(i)

        # 找到分數最大值
        score = [ max(x,y) for x,y in zip(r_white_score,r_black_score) ]

        # 找到分數做大的下標
        chess_index = score.index(max(score))

        print(score,'\n',max(score))

        y = chess_index //19
        x = chess_index % 19

        return QPoint(x,y)

    def autoDown(self):
        '''
        自動落子
        :return:
        '''
        point = self.getPoint()

        # 注意:x,y座標對應
        chess_index = (point.y(), point.x())  # 棋子在棋盤中的下標
        pos = QPoint(50+point.x()*30, 50+point.y()*30) # 棋子在棋盤中的座標

        self.chessman = Chessman(color=self.turnChessColor, parent=self)
        self.chessman.setIndex(chess_index[1], chess_index[0])
        self.chessman.move(pos)
        self.chessman.show()  # 顯示棋子

        # 顯示標識
        self.focusPoint.move(QPoint(pos.x() - 15, pos.y() - 15))
        self.focusPoint.show()
        self.focusPoint.raise_()

        self.chessboard[chess_index[0]][chess_index[1]] = self.chessman

        # 歷史記錄
        self.history.append((chess_index[0], chess_index[1], self.chessman.color))

        # 改變落子顏色
        if self.turnChessColor == 'black':
            self.turnChessColor = 'white'
        else:
            self.turnChessColor = 'black'
        # 判斷輸贏
        result = self.isWin(self.chessman)
        if result != None:
            print(result + '贏了')
            self.showResult(result)

        pass

if __name__ == '__main__':

    import cgitb
    cgitb.enable('text')

    a = QApplication(sys.argv)
    m = SinglePlayerGame()
    m.show()
    sys.exit(a.exec_())

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章