首页 > 其他分享 >基于MCTS的三维四子棋AI模拟和基于PyQt5的应用交互界面

基于MCTS的三维四子棋AI模拟和基于PyQt5的应用交互界面

时间:2024-05-30 16:01:10浏览次数:15  
标签:__ 基于 四子 AI self pc dir poss def

'''
三维四子棋是在三维空间率先四子连珠的游戏,在传统五子棋基本被研究透的情况下,三维四子棋增加了规则和难度,更加考验计算力、空间感、观察力和想象力。
本模块实现三维四子棋的GUI。
仅供学习和参考。
By SoulCheung On May 28th
Email:[email protected]
QQ:1594983583
'''

import sys,os,math,random,psutil
from itertools import product 
from PyQt5 import QtWidgets,QtCore,QtGui
from PyQt5.QtCore import Qt,pyqtSignal,QThread,QObject
from PyQt5.QtGui import QPalette,QPixmap,QIcon
from PyQt5.QtMultimedia import QSound

if os.name == "nt":
    dir = os.path.split(__file__)[0]
board_image=dir+'/assets/board.png'
black_image=dir+'/assets/black.png'
white_image=dir+'/assets/white.png'
br_image=dir+'/assets/blacks-removebg-preview.png'
wr_image=dir+'/assets/whites-removebg-preview.png'
move_sound=dir+'/assets/move.wav'
win_sound=dir+'/assets/win.wav'
defeated_sound=dir+'/assets/defeated.wav'

def overload():
    if psutil.Process(os.getpid()).memory_info().rss/1024/1024/1024>19 or psutil.virtual_memory().percent>92:  
        return True
    else:
        return False

def judge(t,tl):
    for i in tl:
        if abs(t[0]-i[0])<2 and abs(t[1]-i[1])<2 and abs(t[2]-i[2])<2:
            x,y,z=t[0]-i[0],t[1]-i[1],t[2]-i[2]
            if (i[0]-x,i[1]-y,i[2]-z) in tl:
                if (t[0]+x,t[1]+y,t[2]+z) in tl or (i[0]-x*2,i[1]-y*2,i[2]-z*2) in tl:
                    return True
            elif (t[0]+x,t[1]+y,t[2]+z) in tl:
                if (i[0]-x,i[1]-y,i[2]-z) in tl or (t[0]+x*2,t[1]+y*2,t[2]+z*2) in tl:
                    return True
    else:
        return False

def transform(x,y):
    if y in range(50,270):
        y=(y-50)//44
        if x in range(50,270) or x in range(320,540) or x in range(590,810) or x in range(860,1080) or x in range(1130,1350):
            z=x//270
            x=(x-270*z-50)//44
            return (x,y,z)
        else:
            return False
    else:
        return False

def printpos(t):
    x=['A','B','C','D','E']
    y=['1','2','3','4','5']
    z=['一','二','三','四','五']
    return x[t[0]]+y[t[1]]+z[t[2]]

class Player():
    def __init__(self,n,st,et):
        if n == 0:
            self.name='黑'
            self.n=n
        else:
            self.name='白'
            self.n=1
        self.chesslist=[]
        self.ai=False
        self.st=st
        self.et=et

class Node():
    def __init__(self,pc,pd,b):
        super().__init__()
        self.parent = None
        self.children = []
        self.visit_times = 1  
        self.win_times = 0  
        self.situation = None   
        self.n=0  
        self.depth=0  
        self.leaf=False  
        self.pc=pc
        self.pd=pd
        self.board=b

    def set_patnet(self,node):
        self.parent=node
        if self.parent.n==0:
            self.n=1
        else:
            self.n=0
        self.depth=self.parent.depth+1

    def set_children(self):
        for i in self.board:
            new_board=self.board[:]
            if i[2]<4:
                new_board[self.board.index(i)]=(i[0],i[1],i[2]+1)
            newpc=self.pc[:]
            newpc.append(i)
            child=Node(self.pd[:],newpc,new_board)
            child.set_patnet(self)
            child.situation=i
            self.children.append(child)

    def set_leaf(self):
        self.leaf=True

    def ucb(self):
        return self.win_times/self.visit_times+math.sqrt(2*math.log(self.parent.visit_times,math.e)/self.visit_times)

    def chose(self):
        ucb=-1
        l=[]
        for i in self.children:
            if i.leaf==True:  
                l=[i]
                break
            n=i.ucb()
            if n>ucb:
                l=[i]
                ucb=n
            if n==ucb:
                l.append(i)
        return random.choice(l)

    def maxchild(self):
        rate=0.5
        l=[]
        for i in self.children:
            n=i.win_times/i.visit_times
            if n > rate:
                l=[i]
                rate=n
            if n==rate:
                l.append(i)
        return random.choice(l)

class LaBel(QtWidgets.QLabel):
    def __init__(self, parent):
        super().__init__(parent)
        self.setMouseTracking(True)

    def enterEvent(self, e):
        e.ignore()

class Timer(QtWidgets.QLCDNumber):
    TimeOut=pyqtSignal()
    OneSecond=pyqtSignal()
    
    def __init__(self, parent,n:int):
        super().__init__(parent)
        self.time=n
        self.of=False
    
    def resetn(self,n):
        self.time=n

    def start(self):
        self.of=True
        self.ddl=self.startTimer(1000,Qt.PreciseTimer)

    def timerEvent(self, e):
        self.time-=1
        m,s=divmod(self.time,60)
        self.display("%02d:%02d" % (m, s))
        self.OneSecond.emit()
        if self.time<=0:
            self.close()
            self.TimeOut.emit()
        
    def close(self):
        try:
            self.killTimer(self.ddl)
        except AttributeError:
            pass
        self.of=False

class WorkerThread(QThread):
    run_status=True
    
    def __init__(self,node):
        super().__init__()
        self.node=node

    def run(self):
        def postback(node,n):
            lvnode=node
            while True:
                lvnode.visit_times+=1
                if lvnode.n==n:
                    lvnode.win_times+=1
                if lvnode.parent!=None:
                    lvnode=lvnode.parent
                else:
                    break
        while self.run_status:
            if not overload():
                node=self.node
                while not node.leaf:
                    if len(node.children)==0:
                        node.set_children()
                    node=node.chose()
                    if judge(node.situation,node.parent.pc):
                        node.set_leaf()
                        postback(node,node.n)
                        break
            else:
                break

    def stop(self):
        self.run_status=False

class Gobang(QtWidgets.QWidget):
    def __init__(self):
        super(Gobang,self).__init__()
        self.resize(1400, 800)
        self.setMinimumSize(QtCore.QSize(1400,800))
        self.setMaximumSize(QtCore.QSize(1400,800))  
        self.setWindowTitle("三维四子棋")  
        self.setWindowIcon(QIcon(black_image))
        palette1 = QPalette() 
        palette1.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap(board_image)))
        self.setPalette(palette1)
        self.black=QPixmap(black_image)
        self.white=QPixmap(white_image)
        self.ms=QSound(move_sound)
        self.ws=QSound(win_sound)
        self.ds=QSound(defeated_sound)
        self.br=QtWidgets.QLabel(self)
        self.br.setPixmap(QPixmap(br_image))
        self.br.setScaledContents(True)
        self.br.setGeometry(560,400,80,80)
        self.wr=QtWidgets.QLabel(self)
        self.wr.setPixmap(QPixmap(wr_image))
        self.wr.setScaledContents(True)
        self.wr.setGeometry(560,600,80,80)
        self.startbt=QtWidgets.QPushButton('开始',self)
        self.startbt.setGeometry(1150,400,100,35)
        self.startbt.clicked.connect(self.gamestart)
        self.resetbt=QtWidgets.QPushButton('重置',self)
        self.resetbt.setGeometry(1150,500,100,35)
        self.resetbt.clicked.connect(self.initui)
        self.pausebt=QtWidgets.QPushButton('暂停',self)
        self.pausebt.setCheckable(True)
        self.pausebt.toggle()
        self.pausebt.setGeometry(1150,600,100,35)
        self.pausebt.clicked.connect(self.gamepause)
        self.rollbackbt=QtWidgets.QPushButton('悔棋',self)
        self.rollbackbt.setGeometry(1150,700,100,35)
        self.rollbackbt.clicked.connect(self.gamerollback)
        self.bai=QtWidgets.QCheckBox('笨笨的机器人代打',self)
        self.bai.stateChanged.connect(self.aistart)
        self.wai=QtWidgets.QCheckBox('笨笨的机器人代打',self)
        self.wai.stateChanged.connect(self.aistart)
        self.bai.setGeometry(545,490,125,25)
        self.wai.setGeometry(545,690,125,25)
        self.pieces=[LaBel(self) for i in range(125)]
        for piece in self.pieces:
            piece.setVisible(True)
            piece.setScaledContents(True)
        self.bst=Timer(self,90)
        self.bst.setGeometry(700,375,150,60)
        self.bet=Timer(self,900)
        self.bet.setGeometry(700,465,150,60)
        self.bst.TimeOut.connect(self.aiplace)
        self.wst=Timer(self,90)
        self.wst.setGeometry(700,575,150,60)
        self.wet=Timer(self,900)
        self.wet.setGeometry(700,665,150,60)
        self.wst.TimeOut.connect(self.aiplace)
        self.initui()

    def initui(self):   
        self.wet.display('15:00')
        self.wst.display('01:30')
        self.bet.display('15:00')
        self.bst.display('01:30')
        self.startbt.setEnabled(True)
        self.pausebt.setEnabled(False)
        self.bai.setEnabled(True)
        self.wai.setEnabled(True)
        self.bai.setChecked(False)
        self.wai.setChecked(False)
        self.bst.close()
        self.bst.resetn(90)
        self.bet.close()
        self.bet.resetn(900)
        self.wst.close()
        self.wst.resetn(90)
        self.wet.close()
        self.wet.resetn(900)
        for i in self.pieces:
            i.setPixmap(QPixmap(''))
        self.rates=[]
        self.poss=list(tuple(list(i)+[0]) for i in [a for a in product(range(5),repeat=2)])
        for i in self.poss:
            l=QtWidgets.QLabel(self)
            l.setGeometry(50+80*i[0],345+80*i[1],80,80)
            l.setText(printpos(i))
            self.rates.append(l)
        self.gaming=False   
        self.step=0
        self.pl=[Player(0,self.bst,self.bet),Player(1,self.wst,self.wet)]
        self.pc=self.pl[0]
        self.pc.st.OneSecond.connect(self.showrates)
        self.node=Node(self.pc.chesslist[:],self.pl[(self.pl.index(self.pc)+1)%2].chesslist[:],self.poss[:])
        self.ai=WorkerThread(self.node)
        self.ai.start()

    def showrates(self):
        for i in self.node.children:
            self.rates[i.situation[0]*5+i.situation[1]].setText(printpos(i.situation)+'\n'+str(i.win_times)+'/'+str(i.visit_times-1))

    def aistart(self):
        if self.bai.isChecked():
            self.pl[0].ai=True
        else:
            self.pl[0].ai=False
        if self.wai.isChecked():
            self.pl[1].ai=True
        else:
            self.pl[1].ai=False

    def aiplace(self):
        if self.pc.ai:
            self.place(self.node.maxchild().situation,self.step%2)
        else:
            self.pc.et.start()

    def gamestart(self):
        self.gaming=True
        self.startbt.setEnabled(False)
        self.pausebt.setEnabled(True)
        self.bai.setEnabled(False)
        self.wai.setEnabled(False)
        self.bst.start()

    def gamepause(self):
        if self.gaming:
            self.gaming=False
            self.pausebt.setText('恢复')
            if self.pc.st.of:
                self.pc.st.close()
            else:
                self.pc.et.close()
        else:
            self.pausebt.setText('暂停')
            self.gaming=True
            self.pc.st.start()

    def gamerollback(self):
        if len(self.pl[1].chesslist)>0:
            t1=self.pl[0].chesslist[-1][:]
            t2=self.pl[1].chesslist[-1][:]
            self.poss[self.poss.index((t1[0],t1[1],t1[2]+1))]=t1
            self.poss[self.poss.index((t2[0],t2[1],t2[2]+1))]=t2
            for i in self.pl:
                i.chesslist.pop(-1)
            self.pieces[self.step-1].setPixmap(QPixmap(''))
            self.pieces[self.step-2].setPixmap(QPixmap(''))
            self.step-=2

    def place(self,t,flag):
        if flag==0:
            pie=self.black
        else:
            pie=self.white
        self.pieces[self.step].setPixmap(pie)
        self.pieces[self.step].setGeometry(t[0]*44+54+t[2]*270, t[1]*44+54, 36, 36)
        self.ms.play()
        self.step+=1
        if judge(t,self.pc.chesslist):
            self.ws.play()
            self.gaming=False
            self.rollbackbt.setEnabled(False)
            self.pausebt.setEnabled(False)
            if self.pc.st.of:
                self.pc.st.close()
            else:
                self.pc.et.close()
        else:
            self.pc.chesslist.append(t[:])
            if t[2] < 4:
                self.poss[self.poss.index(t)]=(t[0],t[1],t[2]+1)
            else:
                self.poss[self.poss.index(t)]=None
            if self.pc.st.of==False:
                self.pc.et.close()
            else:
                self.pc.st.close()
            self.pc.st.resetn(90)
            self.pc.st.display('01:30')
            self.pc=self.pl[self.step%2]
            self.pc.st.start()
            self.ai.stop()
            self.node=Node(self.pc.chesslist[:],self.pl[(self.pl.index(self.pc)+1)%2].chesslist[:],self.poss[:])
            self.ai=WorkerThread(self.node)
            self.ai.start()
            self.pc.st.OneSecond.connect(self.showrates)

    def mousePressEvent(self, e):
        if self.pc.ai==False:
            if e.button() == Qt.LeftButton and self.gaming==True:
                t=transform(e.x(), e.y())
                if t in self.poss:
                    self.place(t,self.step%2)


if __name__=="__main__":
    app = QtWidgets.QApplication(sys.argv)  
    gb = Gobang()
    gb.show()  
    exit(app.exec_())

资源链接:基于MCTS的三维四子棋AI模拟和基于PyQt5的应用交互界面: 基于MCTS的三维四子棋AI模拟和基于PyQt5的应用交互界面 - Gitee.com

标签:__,基于,四子,AI,self,pc,dir,poss,def
From: https://blog.csdn.net/zhangshuo88/article/details/139326869

相关文章

  • 2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024)
    2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024)会议简介我们诚挚邀请您参加2024年大数据应用、智能控制和软件工程国际会议(BDAICSE2024)。这次会议将在美丽的长沙市举行。本次大会旨在汇聚全球大数据应用、智能控制、软件工程等领域的专家学者,共同探索行业前......
  • AI UI developer by ChatGPT plugin:Tailwind CSS Builder
    AI网页UI开发工程师在ChatGPT插件市场中搜索TailwindCSSBuilder,对话可以直接生成基于tailwindcss的HTML网页:生成的网页结果:生成的网页源代码:点击查看代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport&q......
  • 大模型智力升级:AI的未来之路
    大模型的发展引领了人工智能的新时代,其强大的数据处理和学习能力在医疗、金融、教育等众多领域取得了令人瞩目的成就。然而,随之而来的挑战也不容忽视。尽管大模型在特定任务上展现出了卓越的性能,但它们在理解复杂语境、处理未见情况的能力以及快速适应新环境方面仍显得力不从......
  • 开源VS闭源:AI未来的十字路口
    人工智能领域的发展日益加速,其中关于模型的开源和闭源策略引起了业界的广泛关注。开源策略指的是将软件的源代码公开,允许任何人自由使用、研究甚至改进;而闭源策略则是指软件的源代码不公开,只有特定的个体或组织有权访问和修改。在人工智能尤其是深度学习模型的应用中,开源策略能......
  • 各种“Ops“的对比:DevOps vs. DataOps vs. MLOps vs. AIOps
    文章目录0.前言1.DevOps2.DataOps3.MLOps4.AIOps5.总结6.参考0.前言近年来,缩略词“Ops”在IT运营领域中迅速普及,反映了该领域的一系列重要变革。传统的IT操作正在向自动化流程转变,以更高效地改善客户交付。这种转变旨在减少人为干预,增加操作的一致性......
  • 【已解决】Swagger配置问题—Failed to start bean ‘documentationPluginsBootstrapp
    项目场景:swagger-demo编写SwaggerConfig.java后运行SwaggerDemoApplication.java不能成功问题描述ErrorstartingApplicationContext.Todisplaytheconditionsreportre-runyourapplicationwith'debug'enabled.org.springframework.context.ApplicationCont......
  • 程序员如何避免被ai替代
    程序员不被AI替代的策略:1.持续学习和提升技能:  -关注最新技术趋势和工具,如云计算、人工智能、区块链等。  -掌握多个编程语言和框架,提升全栈开发能力。2.培养跨领域知识:  -理解行业需求,将技术应用于具体行业,如金融科技、医疗信息化等。  -学习产品设计......
  • 线程简述:协程、抢占式、sleep、wait、interrupt,优雅中断线程,线程通信等
    思维导图在此:java线程简述-CSDN博客1、线程与协程协程-->线程-->进程,协程最小协程:用户态,go语言线程:用户态、内核态都有。cpu调度的最小单位。是工人,从进程获取资源,多个线程共享进程的资源。进程:内核态。操作系统调度资源的最小单位。是资源管家。2、调度机制协同式。......
  • 基于Java+Vue的园区智能化管理系统:综合管控,推进数字化转型(代码分享)
    前言:智慧园区管理平台是一个集成了多种功能的综合性系统,旨在通过信息化、智能化手段提升园区的管理效率和服务质量。以下是针对系统的各个功能模块的简要描述:一、楼栋管理会务管理:管理园区内的会议预约、会议室使用等。园区信息:展示园区的基本信息,如位置、面积、规划等。楼......
  • 校园台球厅人员与设备|基于SprinBoot+vue的校园台球厅人员与设备管理系统(源码+数据库
    校园台球厅人员与设备管理系统目录基于SprinBoot+vue的校园台球厅人员与设备管理系统一、前言二、系统设计三、系统功能设计 1系统功能模块2管理员功能模块3用户功能模块四、数据库设计 五、核心代码 六、论文参考七、最新计算机毕设选题推荐八、源码获取:......