用Tkinter模块和极大值-极小值搜索算法编写人机对战五子棋
【话不多说,视频如下】图形化界面的人机对战五子棋
因为录屏的画音不同步哈,看着就有点卡,但其实是不卡的哈
各位观众老爷,怎么样?若觉得可以,请在评论区发一个“666”,若不行请发一个“就这”
【注:本人大一学生一个,初学Python而已[doge],能力有限】
下面就让我来手把手教你如何写一个这样的玩意儿!(完整源码在底下)
【废话少说,直接教学】
【预期目标】
【预期目标】
我们的预期目标是要做一个有棋盘界面,有一定功能的GUI界面化程序,模式设有三种,分别是
【人机模式】这个比较难,主要在于人机的实现和人机与界面化的对接(人机下棋动画)
【对弈模式】这个最简单了,编出界面后随便加几个函数,制定一下游戏规则即可
【机机模式】这个也简单,前提是人机模式要先编出来😅
【功能设置】
功能设有【退出】、【重置】、【悔棋】
退出简单,重置还好、但是悔棋就要一点点技术了(真不太好弄)
界面的优化就是加入了每一步下棋的记录,是谁下的棋,下在了哪个位置,这个也要点技术
还有一个细节,就是鼠标移到棋盘哪个地方,都会有一个亮绿色的显示框
用一个图来展示我的基本编写步骤(我应该没记错)
【棋盘界面】
利用Canvas画布控件添加图片,并按照五子棋棋盘规则(15×15),用循环优化代码,重复画直线,棋盘加一个边框会更好看(如下图),注意细节:不要忘记棋盘里有五个黑点(用实心黑色小圆形实现)
【按钮放置】
这个按钮可不是简单的按钮,它经过了细节优化,同时还用bind函数关联的了鼠标的点击、经过、离开它的事件信息,使得我们把鼠标悬停在它上面时它会改变状态(背景变成白色,如下图),这样就使得它更具有游戏性。
特别说明,点击重置按钮,弹出来的不是一个新的对话框什么的,而是我画的一个模式选择框,为什么要画一个,而不直接引用模块呢?(有模块可以直接用的)我说过,我不喜欢引用很多别人写好的模块(比如:内置模块),此外,引入模块的对话框我不好去修改它的样式,而我自己画的,我可以任意改(方便美化)
【步骤显示板】
这个还好,就是放一个Label标签控件,控制它的大小和位置,加上一些信息显示(模式信息)
【鼠标位置显示框】
这个就比较妙了,我的方法是对整个窗口用bind函数进行关联,关联鼠标每时每刻的位置,当它在我想要的地方时,对其像素坐标(相对于整个窗口,左上角为(0,0)位置)信息进行处理,转化成棋盘坐标,同时画八条直线(如下图),构成我们的鼠标位置显示框,当其棋盘坐标更新的时候,我们就把原来画的的删掉,然后重新定位,再画。当然,也可以移动其位置,但是重画的方法的代码简单(我偷懒了,没有优化代码😅)
【下棋(对弈模式)】
这个其实很简单的,白方定义为先下棋的一方,下白子,黑子也是,但是注意一下,我没有棋子图片的资源文件,所以我自己画一个,很简单,就是一个边框宽度设置为零,定义好内部颜色的,由当前画布控件产生的圆形。
至于游戏规则的制定,简单简单,就是设个变量去存储当前下棋方是谁的信息,每走一步棋就修改它一次,然后由这个变量决定,下一次下的棋子的颜色。下棋的动画(棋子出现在棋盘上)就是通过上面讲到的鼠标位置显示框的棋盘坐标决定的。每次下棋就放置画好的圆形,同时修改棋盘信息存储列表。
这里弄完后就是对弈模式的最后一步了,编写一个函数,分析棋盘数据,判断是否有输赢产生。
我在下面的代码呢,是通过得到棋盘数据并暴力枚举的方法判断输赢的,其实呢,还有一个更简单的判断方法,其实我们并不需要整个棋盘的信息,不然每下一步棋就分析这么多数据,占用时间较多,真正的解决办法是:找到最后一步(这个很容易做到),在以它为中心向八个方向辐射的区域进行判断,因为如果有五子连线,必定在这其中(下图展示的很清楚)
这必定是最简单且快速的判断方法了!
但这是我在写完这个程序后才发现可以这样的,所以下面的源码中我就没有去修改(偷懒了😅)
【下棋步骤记录】
通过记录下棋瞬时鼠标位置的数据,不难得到每次下棋的坐标是哪里,由存储当前下棋方的变量,易知刚刚是谁走了一步棋,最后将信息以字符串形式添加在一个变量里,使它换行的关键在于每次添加的时候顺便加了一个换行符
【编写AI算法】
不用我说,这一步非常难!
说明一下,我写出来之前是不知道有这个什么五子棋人工智能,什么极大值极小值搜索算法的......我当时的想法就是,遍历五子棋所有的可能性,用我提前写好的评估列表数据去匹配,找到最好的走法(用于进攻)和最坏的走法(用于防御),然后让电脑去走就是了。没想到还真有这么个算法,对,就叫极大值-极小值搜索算法!
基本想法就是,把棋盘信息列表中的信息进行提取,分别从横、竖、左斜和右斜四个方向上考虑,提取出所有的五个位置连在一起的小列表(不要求五子相同),去和我已经写好的评估列表匹配,(评估列表中含有这种小列表的局部分数),把所有的分数加起来就是当前棋盘的总得分。好走法要计分,坏走法也要,两者都记为正数,最后作差即可得到当前棋盘的局部分数总和,棋盘的好坏就取决于这个分数!
那么AI要做什么呢?
当我下了一步之后,电脑开始模拟在所有为空子(没有棋子)的地方下一个黑子,下完一次就评估棋盘得分并记录下该黑子的棋盘坐标和棋盘得分,循环操作,直到把225个位置全部遍历,然后找出记录列表中得分的最高的下子位置,即为当前最佳走法!
那么问题来了,这个评估函数怎么搞出来的呢?
评估、评估嘛,它为什么叫评估列表?因为它是用来评估的,它本身的值还是我自己评估的啊🤣,然后再在后面的实践中进行修改(尤其是特殊值!)
其实还可以搜索第二层(电脑模拟人类下白子),这个二就是搜索深度(但是我放弃了),当时我尝试了的,结果AI走一步要计算二十多秒!!!第三层再模拟下黑子就更不用说了,这还玩个毛的游戏啊!所以,在这个速度要改进,推荐用alpha-beta剪枝算法(如下图),可以提高AI的智能性,加快计算速度(准确说叫减少不必要的计算量),感兴趣的小伙伴们自己去了解哈
最后,再加上一点随机数,以处理多种走法但分数相同的情况(如第一步),这样游戏的人机看起来就更加AI了(这也就导致了机机模式下每局电脑与电脑下棋结果大为不同)
【机机模式】
本来是用来给我自己来看人机AI的评估函数还可以怎么改进的,结果倒发现,看两个电脑下棋格外地有意思🤡,有时候真是不知道该说些什么,尤其是刚开始的时候,评估函数分析的评估列表不够完整,那个人工智能走的那个棋啊,简直不堪入目!!!这怕不是人工智障吧!!!🤣随着我一点一点地修改,这种情况的出现少了很多
其实还有个很妙的想法,暂时还没有实现,就是让修改评估列表的事也交给电脑程序去完成,也就是说,让程序自己运行,自己发现问题,自己去适当地修改评估列表,再将新的评估列表直接使用,依次类推... ...,那么我只需要把电脑打开,让它运行个十天八天的,大量的数据面前,评估列表的修改必然会符合统计学数学规律,类似于高中的求回归方程,最后的评估列表就相当于那个回归方程,会非常的精准,不知道这种方法叫什么名字呢?
【音乐添加】
这里不做过多解释,主要用Pygame实现,(主要是我也不是很了解Pygame😅)
【多说无益,且看源码】
from tkinter import * from random import * import pygame pygame.mixer.init() game = Tk() game.geometry('960x480+150+100') game.title('五子棋') game.resizable(0,0) background = PhotoImage(file='resources\\fivechess2.png') pygame.mixer.music.load('resources\\fivechessbgm.mp3') pygame.mixer.music.set_volume(0.1) class fivechess: def __init__(self):#定义必要变量 self.game7 = Frame(game) self.canvas = Canvas(self.game7) self.px,self.py = 960,480 self.text = ''#下棋记录 self.lists = []#棋盘存储列表 self.cold = 0#冷却值,0白方回合,1黑方回合 self.mode = 0#0默认为人机对战 self.color = 'white'#默认白子先走 self.value = 1#0为空子;1为白子;2为黑子 self.Count = 0#步数 self.over = 0#决定游戏是否结束 self.buttontext = '人机模式' self.regretlis = []#可悔棋列表 self.regretlisxy = []#可悔棋坐标列表 self.T = StringVar() self.t = 15#初始剩余时间数 self.ty = 150#时间标签初始纵坐标 self.Mode = StringVar() self.Mode.set('人机模式') self.function() def function(self):#启动功能 self.lists = [[0]*15 for _ in range(15)] self.game7.place(width=960,height=480) self.canvas.place(width=960,height=480) self.canvas.create_image(500,250,image=background) self.canvas.bind('<Button-1>',lambda event:self.player()) self.canvas.bind('<Motion>',lambda event:self.position(event)) self.modeset() self.initialization1() self.initialization2() self.AI_initialization() def initialization1(self,color='black'):#棋盘初始化 for i in range(256,705,32):#棋盘网 (256,16)~(704,464) self.canvas.create_line(i,16,i,464) self.canvas.create_line(256,i-240,704,i-240) self.canvas.create_rectangle(250,10,710,470,width=3)#棋盘框 self.canvas.create_oval(349,109,355,115,fill=color)#棋盘点 self.canvas.create_oval(349,365,355,371,fill=color) self.canvas.create_oval(605,109,611,115,fill=color) self.canvas.create_oval(605,365,611,371,fill=color) self.canvas.create_oval(477,237,483,243,fill=color) def position(self,event,color='springgreen'):#鼠标位置 if 240< event.x <720: self.px,self.py = 32*int((event.x-240)/32)+256,32*int(event.y/32)+16 try: for i in [self.l1,self.l2,self.l3,self.l4,self.l5,self.l6,self.l7,self.l8]:self.canvas.delete(i) except:pass self.l1 = self.canvas.create_line(self.px-15,self.py-15,self.px-15,self.py-5,width=1,fill=color) self.l2 = self.canvas.create_line(self.px-15,self.py-15,self.px-5,self.py-15,width=1,fill=color) self.l3 = self.canvas.create_line(self.px-15,self.py+15,self.px-15,self.py+5,width=1,fill=color) self.l4 = self.canvas.create_line(self.px-15,self.py+15,self.px-5,self.py+15,width=1,fill=color) self.l5 = self.canvas.create_line(self.px+15,self.py-15,self.px+15,self.py-5,width=1,fill=color) self.l6 = self.canvas.create_line(self.px+15,self.py-15,self.px+5,self.py-15,width=1,fill=color) self.l7 = self.canvas.create_line(self.px+15,self.py+15,self.px+5,self.py+15,width=1,fill=color) self.l8 = self.canvas.create_line(self.px+15,self.py+15,self.px+15,self.py+5,width=1,fill=color) def initialization2(self): Label(self.game7,bg='grey',font=('consolas',30),text='白方',fg='white').place(width=200,height=200,x=20,y=20) Label(self.game7,bg='grey',font=('consolas',30),text='黑方',fg='white').place(width=200,height=200,x=20,y=260) self.f1 = Label(self.game7,bg='black') self.f2 = Label(self.game7,bg='black') self.f3 = Label(self.game7,bg='black') self.f4 = Label(self.game7,bg='black') self.f(10) Label(self.game7,bg='black').place(width=220,height=280,y=10,x=730) Label(self.game7,bg='grey').place(width=216,height=276,y=12,x=732) Label(self.game7,bg='grey',textvariable=self.Mode,font=('consolas',15),fg='white').place(width=216,height=26,y=12,x=732) countframe = Frame(self.game7,bg='grey') countframe.place(width=216,height=250,x=732,y=38) self.countlabel = Label(countframe,bg='grey',fg='white',text=self.text,font=('consolas',12),anchor='sw') self.timelabel = Label(self.game7,bg='grey',textvariable=self.T,fg='white',font=('consolas',30)) self.B1 = Button(self.game7,bg='grey',bd=0,font=('consolas',20),fg='white',text='退出',command=self.game7.quit) self.B1.place(width=220,x=730,height=50,y=300) self.B2 = Button(self.game7,bg='grey',bd=0,font=('consolas',20),fg='white',text='重置',command=lambda:gameagain()) self.B2.place(width=220,x=730,height=50,y=360) self.B3 = Button(self.game7,bg='grey',bd=0,font=('consolas',20),fg='white',text='悔棋',command=lambda:self.regret(),state='disabled') self.B3.place(width=220,x=730,height=50,y=420) for i in [self.B1,self.B2,self.B3]: i.bind('<Enter>',lambda event:enter(event)) i.bind('<Leave>',lambda event:leave(event)) def enter(event):event.widget['bg']='#F0F0F0';event.widget['fg']='black' def leave(event):event.widget['bg']='grey';event.widget['fg']='white' def gameagain(): self.game7.destroy() fivechess() def f(self,fy): self.f1.place(width=5,height=220,x=10,y=fy) self.f2.place(width=220,height=5,x=10,y=fy) self.f3.place(width=220,height=5,x=10,y=fy+215) self.f4.place(width=5,height=220,x=225,y=fy) def AI_initialization(self): self.defense_case =[[0,0,0,0,0],#0 [0,0,1,0,0], [0,1,0,0,0], [1,0,0,0,0], [1,0,0,1,0], [0,0,1,1,0],#5 [0,1,0,1,0], [1,0,1,0,0], [1,0,0,0,1], [0,0,0,1,1], [1,1,0,0,1],#10 [0,1,1,0,1], [0,1,0,1,1], [1,0,1,0,1], [1,1,1,0,0], [0,1,1,1,0],]#15 self.attack_case = [[0,0,0,0,0],#0 [0,0,2,0,0], [0,2,0,0,0], [2,0,0,0,0], [2,0,0,2,0], [0,0,2,2,0],#5 [0,0,2,2,0], [2,0,2,0,0], [0,2,0,2,0], [0,0,0,2,2], [2,2,0,0,2],#10 [0,2,0,2,2], [0,2,2,0,2], [2,0,2,0,2], [2,2,2,0,0], [0,2,2,2,0],]#15 def defense(self,lis,value=0): if 0 in lis and lis.count(1) == 4:value = 9999999999 elif 2 in lis and lis.count(1) == 4:value = 5000 elif lis == [0,1,1,1,0]:value = 9999999 elif lis in [[1,1,0,1,0],[0,1,1,0,1]] or reversed(lis) in [[1,1,0,1,0],[0,1,1,0,1]]:value = 10000 else: try:value = self.defense_case.index(lis)**3 except: try:value = self.defense_case.index(reversed(lis))**3 except:pass return value def defense2(self,lis,value=0): if lis == [0,0,1,1,1,0] or lis == [0,1,1,1,0,0]:value = 999999999 elif lis in [[0,1,1,1,1,2],[1,0,1,1,1,2],[1,1,0,1,1,2],[1,1,1,0,1,2],[2,1,0,1,1,1,],[2,1,1,0,1,1],[2,1,1,1,0,1],[2,1,1,1,1,0]]:value = 99999999 elif lis in [[1,1,1,1,0,1],[1,0,1,1,1,1]]:value = 9999999 return value def attack2(self,lis,value=0): if lis == [1,2,2,2,2,1]:value = -99999 elif lis == [0,2,2,2,2,1] or lis == [1,2,2,2,2,1]:value = 9999 elif lis == [0,2,2,2,2,0]:value = 9999999999 elif lis == [0,2,2,0,2,0] or lis == [0,2,0,2,2,0]:value = 999999 return value def attack(self,lis,value=0): if lis == [2]*5:value=9999999999 elif 0 in lis and lis.count(2) == 4:value = 9999999 elif 1 in lis and lis.count(2) == 4:value = -1000 elif lis == [0,1,1,1,0]:value = -10000 elif lis in [[2,1,1,0,2],[2,0,1,1,1],[2,1,1,1,0],[2,1,0,1,2],[2,1,1,1,2]] or reversed(lis) in [[2,1,1,0,2],[2,0,1,1,1],[2,1,1,1,0],[2,1,1,1,2]]:value = -300000 elif lis in [[2,1,2,2,0],[2,1,2,2,2]] or reversed(lis) in [[2,1,2,2,0],[2,1,2,2,2]]:value = -30000 elif lis in [[2,2,0,2,0],[0,2,2,0,2],[0,2,2,2,0]] or reversed(lis) in [[2,2,0,2,0],[0,2,2,0,2]]:value = 4000 else: try:value = self.attack_case.index(lis)**3 except: try:value = self.attack_case.index(reversed(lis))**3 except:pass return value def regret(self): self.B3.config(state='disabled') if self.Count%2 == 0: self.Count -= 2 self.text = self.text[:-40] self.countlabel.config(text=self.text) self.countlabel.place(width=216,height=20*self.Count,y=250-20*self.Count) for i in self.regretlis:self.canvas.delete(i) for i in self.regretlisxy:self.lists[i[0]][i[1]] = 0 try: self.winlabel.destroy() pygame.mixer.music.unpause() self.over = 0 self.mode = 1 if self.buttontext == '对弈' else 0 except:pass def Time(self,updata=0): if updata == 1: self.timelabel.config(fg='white') self.t = 15 self.ty = 150 if self.ty == 390 else 390 self.T.set('- %s -'%self.t) self.timelabel.place(width=200,height=30,x=20,y=self.ty) if self.t == 2 and self.mode != 2: self.timelabel.config(fg='red') pygame.mixer.Sound('resources\\ring.wav').play() if self.t != 0 and updata == 0: self.t -= 1 self.game7.after(1000,self.Time) def modeset(self): self.MS = Frame(self.game7) self.MS.place(width=300,height=200,y=140,x=330) Label(self.MS,bg='black').place(width=280,height=90,x=10,y=70) textlabel = Label(self.MS,bg='grey',font=('consolas',15),fg='white',text='人类与电脑之间的战斗!\n不怕死就来挑战吧!') textlabel.place(width=276,height=86,x=12,y=72) b1 = Button(self.MS,text=self.buttontext,font=('consolas',20),bd=0,command=lambda:button()) b1.place(width=200,height=30,y=35,x=50) Label(self.MS,bg='grey',text='设置',font=('consolas',15)).place(width=300,height=30) Label(self.MS,bg='grey').place(width=300,height=30,y=170) Button(self.MS,text='确定',font=('consolas',15),bd=0,command=lambda:okget()).place(width=100,height=20,y=175,x=195) def okget(): pygame.mixer.music.play(loops=10) self.MS.destroy() self.Time() if self.mode == 2: self.cold = 1 self.f(500) self.ty = 500 self.AI_AI() def button(): if self.buttontext=='机机模式': self.buttontext = '人机模式' self.mode = 0 self.Mode.set('人机模式') textlabel.config(text='人类与电脑之间的战斗!\n不怕死就来挑战吧!') elif self.buttontext=='人机模式': self.buttontext = '对弈模式' self.mode = 1 self.Mode.set('对弈模式') textlabel.config(text='人类与人类之间的对决!\n到底谁才是王中王呢!') elif self.buttontext == '对弈模式': self.buttontext = '机机模式' self.mode = 2 self.Mode.set('机机模式') textlabel.config(text='电脑与电脑之间的交流!\n一种神秘而牛逼的设定!') b1.config(text=self.buttontext) def enter(event):event.widget['bg']='grey';event.widget['fg']='white' def leave(event):event.widget['bg']='#F0F0F0';event.widget['fg']='black' b1.bind('<Enter>',enter) b1.bind('<Leave>',leave) def referee(self,lists,M=1):#判断输赢M为1就非AI AIlist = [] #竖 for i in range(15): temp_list = [] for lis in lists:temp_list.append(lis[i]) if M == 1:self.judgement(temp_list) else:AIlist.append(temp_list) #横 for lis in lists: if M == 1:self.judgement(lis) else:AIlist.append(lis) #斜 for i in [1,-1]:#右斜;左斜 for x in range(15): y = 0 temp_list1 = [] temp_list2 = [] try: while x >= 0: temp_list1.append(lists[x][y]) temp_list2.append(lists[i*(y-7)+7][i*(x-7)+7]) x += i y += 1 except:pass if M == 1: self.judgement(temp_list1) self.judgement(temp_list2) else: AIlist.append(temp_list1) AIlist.append(temp_list2) return AIlist def judgement(self,lis): try: for i in range(11): if lis[i:i+5] == [1]*5:self.gameover(1);return None if lis[i:i+5] == [2]*5:self.gameover(2);return None except:pass def gameover(self,winner):#winner=1则白方胜,2则黑方胜 pygame.mixer.music.pause() if winner == 1: if self.mode == 0:pygame.mixer.Sound('resources\\victory.wav').play() self.winlabel = Label(self.game7,bg='grey',font=('consolas',30),fg='springgreen',text='-白方胜-') self.winlabel.place(width=200,height=50,x=20,y=40) else: if self.mode == 0:pygame.mixer.Sound('resources\\defeat.wav').play() self.winlabel = Label(self.game7,bg='grey',font=('consolas',30),fg='springgreen',text='-黑方胜-') self.winlabel.place(width=200,height=50,x=20,y=280) if self.mode == 1:pygame.mixer.Sound('resources\\victory.wav').play() self.over = 1#锁定玩家 self.mode = 2#锁定AI def countadd(self,n,x,y): self.Count += 1 player = '[白方]' if n == 1 else '[黑方]' self.text += '\n%s(%02d,%02d)\t [%03d]'%(player,x+1,15-y,self.Count) self.countlabel.config(text=self.text) self.countlabel.place(width=216,height=20*self.Count,y=250-20*self.Count) def regretadd(self,i,x,y): self.regretlis.append(i) self.regretlisxy.append((x,y)) if len(self.regretlis) >= 2:self.B3.config(state='active') if len(self.regretlis) == 3: del self.regretlis[0] del self.regretlisxy[0] def player(self): if self.cold+self.over == 0: x,y = (self.px-256)//32,(self.py-16)//32 if self.lists[x][y] == 0:self.lists[x][y] = self.value else:return None self.countadd(self.value,x,y) i = self.canvas.create_oval(self.px-15,self.py-15,self.px+15,self.py+15,fill=self.color,width=0) self.regretadd(i,x,y) pygame.mixer.Sound('resources\\%s.mp3'%randint(1,4)).play() self.referee(self.lists) self.cold = 1 if self.mode == 0: self.f(250) self.ai_execute() self.Time(updata=1) elif self.mode == 1: if self.color == 'black': self.color = 'white' self.value = 1 self.f(10) else: self.color = 'black' self.value = 2 self.f(250) self.cold = 0 self.Time(updata=1) def ai_execute(self,color='black'): ai_x,ai_y = self.AI() if color == 'black': self.lists[ai_x][ai_y] = 2 self.countadd(2,ai_x,ai_y) else: self.lists[ai_x][ai_y] = 1 self.countadd(1,ai_x,ai_y) ai_x,ai_y = 32*ai_x+256,ai_y*32+16 i = self.canvas.create_oval(ai_x-15,ai_y-15,ai_x+15,ai_y+15,fill=color,width=0) self.regretadd(i,(ai_x-256)//32,(ai_y-16)//32) pygame.mixer.Sound('resources\\%s.mp3'%randint(1,4)).play() if self.mode == 0: self.cold = 0 self.f(10) self.Time(updata=1) self.referee(self.lists) def AI(self): xlis,ylis = [],[] AIdata,AIvalue = [],[] try: for lis in self.lists: for i in lis: if i != 0: xlis.append(self.lists.index(lis)) ylis.append(lis.index(i)) xmax,ymax,xmin,ymin = max(xlis)+4,max(ylis)+4,min(xlis)-4,min(ylis)-4 except:xmax,ymax,xmin,ymin = 20,20,-5,-5 for x in range(15): for y in range(15): if self.lists[x][y] == 0 and xmin<x<xmax and ymin<y<ymax: a_value,d_value = 0,0 self.lists[x][y] = 2 for lis in self.referee(self.lists,M=0): for i in range(11): try: d_value += self.defense(lis[i:i+5]) d_value += self.defense2(lis[i:i+6])#强化 except:pass try: a_value += self.attack(lis[i:i+5]) a_value += self.attack2(lis[i:i+6])#强化 except:pass AIdata.append([x,y]) AIvalue.append(a_value-d_value) self.lists[x][y] = 0 keyvalue = max(AIvalue) N = AIvalue.count(keyvalue) if N == 1:return AIdata[AIvalue.index(keyvalue)] else: for i in range(len(AIvalue)): try: value = AIvalue[i] if value != keyvalue:AIdata.remove(AIdata[i]) except:pass return choice(AIdata) def AI_AI(self): if self.over == 0: color = 'white' if self.Count%2 == 0 else 'black' self.ai_execute(color) self.referee(self.lists) self.game7.after(1000,self.AI_AI) fivechess() game.mainloop()