N年前用python写的五子棋游戏,电脑执白子,只能判断一步,新手级别(可以再添加几层循环让它厉害一点) 。程序的UI界面是用python的标准库 Tkinter 写的,有点乱,现在已然看不懂。
代码如下,可以在py2.7 下运行:
#-*-coding:utf-8-*-
from tkinter import *
import tkMessageBox
#以下为AI部分:
N=17 #棋盘规格 N*N
class Chessboard:
def __init__(self,n=N):
self.N = n
self.count=0 #棋盘上双方棋子总数
self.info={} #棋子信息
for i in range(-(n//2),n//2+1):
for j in range(-(n//2),n//2+1):
self.info.setdefault((i,j)) #info的键的格式为(x,y)。(0,0)处为天元
def add_chess(self, x,y,camp): #x,y为棋子的逻辑坐标,camp(阵营)取值为1或-1。
self.info[(x,y)]=camp
self.count+=1
def cancel_add(self): #退回前一状态。
if self.count>0:
self.count -=1
self.info[self.savedfile[1][-1]]=None
def restart(self):#?
self.__init__(N)
chessboard=Chessboard()#N=19 #棋盘规格 N*N
#
def dead(L): #是否为“死N”,是返回1。!!!别弄反了!!!
if len(L)<5:return 1
return 0
def five(L): #是否为成五,是返回1,否返回0
c=0
for item in L:
if item==0:c=0
else :c+=1
if c==5:return 1
return 0
def four(L): #是否冲四,双四,分别返回1,2,无则0
c=0
index=[]
for i in range(len(L)):
if L[i]==0:
index.append(i) #index记录L中项为0处的索引
for i in range(len(index)):
if i==0:
L[index[0]]=1
if five(L[:index[0]+5])==1:
c=1
else:
L[index[i-1]]=0
L[index[i]]=1
if five(L[index[i-1]+1:index[i]+5])==1:#稍微提高效率,且不会重复,不会遗漏
c+=1
if c==2:
L[index[i]]=0
return 2
if c==1:
L[index[-1]]=0
return 1
L[index[-1]]=0# somewhere wrong?
return 0
def three(L): #是否双活三、活三、眠三,分别返回3,2,1,无则0
c1=c2=0 #c1为活三个数,c2为眠三数(上限1),无则0
index=[]
for i in range(len(L)):
if L[i]==0:
index.append(i) #index记录L中项为0处的索引
for i in range(len(index)):
if i==0:
L[index[0]]=1
temp=four(L[:index[0]+5])#提升效率
if temp==2:
c1=1
elif temp==1:
c2=1
else:
L[index[i-1]]=0
L[index[i]]=1
temp=four(L[(index[i]-4 if index[i]>=4 else 0):index[i]+5]) #应用条件表达式。避免遗漏
if temp==2:
c1+=1
if c1==2:
L[index[i]]=0
return 3 #双活三
elif temp==1:
c2=1
if c1==1:
L[index[-1]]=0
return 2 #活三
if c2==1:
L[index[-1]]=0
return 1 #眠三
L[index[-1]]=0
return 0
def two(L): #双活二返回3,活二返回2,眠二返回1, 无则记为0
index=[]
for i in range(len(L)):
if L[i]==1:
index.append(i) #列表index记录L中值为1的项的索引,len(index) 为L中1的个数
if len(index)==3 and index[2]-index[0] <5 or len(index)>3:
return 0 #无活二或眠二
if len(index)==1:return 0 #无
if len(L)==5:return 1 #眠二
if len(index)==2:
if index[0]==0 or index[1]==len(L)-1 :return 1 #眠二(10001形暗含在其中)
else: return 2 #活二
if len(index)==3 and len(L)>=8: #and 后面的条件取消也可。不知道效率哪个高
double_livetwo=([0,1,0,0,1,0,0,1,0],[0,1,0,0,1,0,1,0,0],[0,0,1,0,1,0,0,1,0],\
[0,0,1,0,0,1,0,1,0],[0,1,0,1,0,0,1,0,0]) #单线双活二
if L in double_livetwo:
return 3 #双活二
if len(index)==3:
if index[0]==0 and index[2]==len(L)-1:
return 1 # 两个组合皆为眠二,返回眠二
else: return 2 #否则,返回活二
def one(L): #活一返回2,眠一返回1,无返回0。
lenth=len(L)
c=0 #c 记录1的个数,c至少会为1(评估点)。
for i in range(lenth):
if L[i]==1:
c+=1
index=i #index记录1的索引
if c==2:return 0
if lenth==5 or index in (0,lenth-1):return 1 #眠一
else: return 2 #活一
#
V_five=9999000000 # 成五
V_db_four=333000000 #活四或双冲四
V_s_four=62500000 #冲四
V_dbl_three=2500000 #双活三
V_live_three=1250000 #活三
V_sleep_three=125000 #眠三
V_dbl_two=5000 #双活二
V_live_two=2500 #活二
V_sleep_two=250 #眠二
V_live_one=10 #活一
V_sleep_one=1 #眠一
V_dead=0 #死N
#列表评估函数,计算出数值结果
def L_eval(L):
if dead(L)==1: return 0
if five(L)==1: return V_five
result=four(L)
if result==2: return V_db_four
elif result==1: return V_s_four
result=three(L)
if result==3: return V_dbl_three
elif result==2: return V_live_three
elif result==1: return V_sleep_three
result=two(L)
if result==3: return V_dbl_two
elif result==2: return V_live_two
elif result==1: return V_sleep_two
result=one(L)
if result==2: return V_live_one
elif result==1: return V_sleep_one
#
#
def Line_eval(camp_1,camp_2,L1,L2,camp): #deal with two list on a line
if camp_1==camp:
if camp_2 ==camp or camp_2=="not found":
L1.pop()
return L_eval(L1+L2)
else: return L_eval(L1)+L_eval(L2)/5.0
elif camp_1=="not found":
if camp_2==camp:
L1.pop()
return L_eval(L1+L2)
elif camp_2 == "not found":
L1.pop()
return 1.2 * L_eval(L1+L2) #L_eval(L1+L2)+L_eval(L1+L2)/5.0
else:
L1.pop()
return L_eval(L1+L2) / 5.0
else:
if camp_2==camp:
return L_eval(L1) / 5.0+L_eval(L2)
else :
L1.pop()
return L_eval(L1+L2)/5.0
def evaluate(x,y,camp,info):#评估camp方在(x,y)处落子的价值
#L1为一边评估列表,L2为另一边边评估列表。
# 0度水平阳线上:
L1,L2,camp_1,camp_2=[1],[1],"not found","not found"
for i in range(x-1,x-5,-1):
if i<-(N//2):break #不能越出棋盘边界
if info[(i,y)]==None:L1.insert(0,0)
else:
index=i #index 记录向一端搜索出的第一个非空闲点的坐标分量
camp_1=info[(index,y)] #向一端搜索出的第一个非空闲点的阵营
L1.insert(0,1)
break
if camp_1!="not found":
for i in range(index-1,x-5,-1):
if i<-(N//2):break #不能越出棋盘边界
if info[(i,y)]==camp_1: L1.insert(0,1)
elif info[(i,y)]==None: L1.insert(0,0)
else: break #此端方向上的搜索完毕。
for i in range(x+1,x+5):
if i>(N//2):break #不能越出棋盘边界
if info[(i,y)]==None:L2.append(0)
else:
index=i #index记录向另一端搜索出的第一个非空闲点的坐标分量
camp_2=info[(index,y)] #向另一端搜索出的第一个非空闲点的阵营
L2.append(1)
break
if camp_2!="not found":
for i in range(index+1,x+5):
if i>(N//2):break #不能越出棋盘边界
if info[(i,y)]==camp_2: L2.append(1)
elif info[(i,y)]==None: L2.append(0)
else: break #此线上的搜索完毕。
V0=Line_eval(camp_1,camp_2,L1,L2,camp)
if V0>=V_five: return V_five
#90度阳线
L1,L2,camp_1,camp_2=[1],[1],"not found","not found"
for i in range(y-1,y-5,-1):
if i<-(N//2):break #不能越出棋盘边界
if info[(x,i)]==None:L1.insert(0,0)
else:
index=i #index 记录向一端搜索出的第一个非空闲点的坐标分量
camp_1=info[(x,index)] #向一端搜索出的第一个非空闲点的阵营
L1.insert(0,1)
break
if camp_1!="not found":
for i in range(index-1,y-5,-1):
if i<-(N//2):break #不能越出棋盘边界
if info[(x,i)]==camp_1: L1.insert(0,1)
elif info[(x,i)]==None: L1.insert(0,0)
else: break #此端方向上的搜索完毕。
for i in range(y+1,y+5):
if i>(N//2):break #不能越出棋盘边界
if info[(x,i)]==None:L2.append(0)
else:
index=i #index记录向另一端搜索出的第一个非空闲点的坐标分量
camp_2=info[(x,index)] #向另一端搜索出的第一个非空闲点的阵营
L2.append(1)
break
if camp_2!="not found":
for i in range(index+1,y+5):
if i>(N//2):break #不能越出棋盘边界
if info[(x,i)]==camp_2: L2.append(1)
elif info[(x,i)]==None: L2.append(0)
else: break #此线上的搜索完毕。
#print (L1,L2)
V90=Line_eval(camp_1,camp_2,L1,L2,camp)
if V90>=V_five: return V_five
#45度阴线
L1,L2,camp_1,camp_2=[1],[1],"not found","not found"
for (i,j) in zip(range(x-1,x-5,-1),range(y-1,y-5,-1)):
if i<-(N//2) or j<-(N//2):break #不能越出棋盘边界
if info[(i,j)]==None:L1.insert(0,0)
else:
index=(i,j) #index 记录向一端搜索出的第一个非空闲点的坐标分量
camp_1=info[index] #向一端搜索出的第一个非空闲点的阵营
L1.insert(0,1)
break
if camp_1!="not found":
for (i,j) in zip(range(index[0]-1,x-5,-1),range(index[1]-1,y-5,-1)):
if i<-(N//2) or j<-(N//2):break #不能越出棋盘边界
if info[(i,j)]==camp_1: L1.insert(0,1)
elif info[(i,j)]==None: L1.insert(0,0)
else: break #此端方向上的搜索完毕。
for (i,j) in zip(range(x+1,x+5,1),range(y+1,y+5,1)):
if i>(N//2) or j>(N//2):break #不能越出棋盘边界
if info[(i,j)]==None:L2.append(0)
else:
index=(i,j) #index记录向另一端搜索出的第一个非空闲点的坐标分量
camp_2=info[index] #向另一端搜索出的第一个非空闲点的阵营
L2.append(1)
break
if camp_2!="not found":
for (i,j) in zip(range(index[0]+1,x+5,1),range(index[1]+1,y+5,1)):
if i>(N//2) or j>(N//2):break #不能越出棋盘边界
if info[(i,j)]==camp_2: L2.append(1)
elif info[(i,j)]==None: L2.append(0)
else: break #此线上的搜索完毕。
#print (L1,L2)
V45=Line_eval(camp_1,camp_2,L1,L2,camp)
if V45>=V_five: return V_five
#135度阴线
L1,L2,camp_1,camp_2=[1],[1],"not found","not found"
for (i,j) in zip(range(x-1,x-5,-1),range(y+1,y+5,1)):
if i<-(N//2) or j>(N//2):break #不能越出棋盘边界
if info[(i,j)]==None:L1.insert(0,0)
else:
index=(i,j) #index 记录向一端搜索出的第一个非空闲点的坐标分量
camp_1=info[index] #向一端搜索出的第一个非空闲点的阵营
L1.insert(0,1)
break
if camp_1!="not found":
for (i,j) in zip(range(index[0]-1,x-5,-1),range(index[1]+1,y+5,1)):
if i<-(N//2) or j>(N//2):break #不能越出棋盘边界
if info[(i,j)]==camp_1: L1.insert(0,1)
elif info[(i,j)]==None: L1.insert(0,0)
else: break #此端方向上的搜索完毕。
for (i,j) in zip(range(x+1,x+5,1),range(y-1,y-5,-1)):
if i>(N//2) or j<-(N//2):break #不能越出棋盘边界
if info[(i,j)]==None:L2.append(0)
else:
index=(i,j) #index记录向另一端搜索出的第一个非空闲点的坐标分量
camp_2=info[index] #向另一端搜索出的第一个非空闲点的阵营
L2.append(1)
break
if camp_2!="not found":
for (i,j) in zip(range(index[0]+1,x+5,1),range(index[1]-1,y-5,-1)):
if i>(N//2) or j<-(N//2):break #不能越出棋盘边界
if info[(i,j)]==camp_2: L2.append(1)
elif info[(i,j)]==None: L2.append(0)
else: break #此线上的搜索完毕。
#print (L1,L2)
V135=Line_eval(camp_1,camp_2,L1,L2,camp)
if V135>=V_five: return V_five
#四条线上评估值耦合,因棋形评估值的特殊性,这里简单的取和
V=V0+V90+V45+V135
return V
#一下是UI部分(初稿):
class CV(Canvas):
def __init__(self, n, master=Tk(), cnf={}, **kw):
Canvas.__init__(self,master,cnf,**kw)
self.size={"N":n,"dx":48,"dy":48,"line_width":2,"padx":24,"pady":24}
self.master_configure()
self.configure(bg="#B84",width=(self.size["N"]-1)*self.size["dx"]+2*self.size["padx"],\
height=(self.size["N"]-1)*self.size["dy"]+2*self.size["pady"],cursor="hand2")
self.create_chessboard()
self.pack()
def create_chessboard(self,tags=("chessboard",)):
padx,pady,dx,dy,line_width,N=self.size["padx"],self.size["pady"],\
self.size["dx"],self.size["dy"],\
self.size["line_width"],\
self.size["N"]
for i in range(N):
self.create_line(padx,pady+dy*i,padx+dx*(N-1),pady+dy*i,\
width=line_width,tags=tags)
self.create_line(padx+dx*i,pady,padx+dx*i,pady+dy*(N-1),\
width=line_width,tags=tags)
d,f,w=5,20,1#about sepcial point
for xy in [ (padx+N//2*dx,pady+N//2*dy),(padx+3*dx,pady+3*dy),\
(padx+(N-4)*dx,pady+3*dy),(padx+3*dx,pady+(N-4)*dy),\
(padx+(N-4)*dx,pady+(N-4)*dy) ]:
self.create_line(xy[0]-f,xy[1]+d,xy[0]-d,xy[1]+d,xy[0]-d,xy[1]+f,width=w)
self.create_line(xy[0]-f,xy[1]-d,xy[0]-d,xy[1]-d,xy[0]-d,xy[1]-f,width=w)
self.create_line(xy[0]+f,xy[1]+d,xy[0]+d,xy[1]+d,xy[0]+d,xy[1]+f,width=w)
self.create_line(xy[0]+f,xy[1]-d,xy[0]+d,xy[1]-d,xy[0]+d,xy[1]-f,width=w)
def plot_chessman(self,x,y,camp): #(x,y):棋子圆心
r = 23 #radius
if camp==1:
o_color="purple"
i_color="black"
else:
o_color="green"
i_color="white"
self.delete("latest")
self.create_oval((x-r,y-r,x+r,y+r),tags=("chessman",),outline=\
o_color,width=1,fill=i_color) #create chessman
self.create_oval((x-r,y-r,x+r,y+r),tags="latest",outline="red",width=3)#mark the latest chessman
def master_configure(self):
self.master["cursor"]="heart"
self.master.title("联珠")
def restart(self):
self.delete("chessman")
self.delete("latest")
renju=CV(N)
def add_chessman(event):
padx,pady,dx,dy,line_width,N=renju.size["padx"],renju.size["pady"],renju.size["dx"],renju.size["dy"],\
renju.size["line_width"],renju.size["N"]
benchmark=(padx+N//2*dx,pady+N//2*dy)
Lx=int((event.x-benchmark[0]+0.5*dx)//dx)
Ly=int((-event.y+benchmark[1]+0.5*dy)//dy)
if (chessboard.count)%2==0 and chessboard.count< N*N:
if (Lx,Ly) in [k for k in chessboard.info if (chessboard.info)[k]==None]: #!!!!!!!!!!!!!!!
renju.plot_chessman(benchmark[0]+Lx*dx,benchmark[1]-Ly*dy,camp=1)
chessboard.add_chess(Lx,Ly,1) ##
renju.unbind("<Button-1>")
if evaluate(Lx,Ly,camp=1,info=chessboard.info)>=V_five: #human
if tkMessageBox.showinfo(title="xixi",message="恭喜你赢了!"):
chessboard.restart()
renju.restart()
if (chessboard.count)%2==1 and (chessboard.count)< N*N:
maxv=0
for (x,y) in [k for k in chessboard.info if (chessboard.info)[k]==None]:
V=evaluate(x,y,camp=-1,info=chessboard.info) # computer
###chessboard.info[(x,y)]=camp
if V>maxv:
#print (x,y), V######################
maxv=V
choice=(x,y)
#print################################
renju.plot_chessman(benchmark[0]+choice[0]*dx,benchmark[1]-choice[1]*dy,camp=-1)
chessboard.add_chess(choice[0],choice[1],-1) ##
if maxv>=V_five:
if tkMessageBox.showinfo(title="haha",message="小白赢了!"):
chessboard.restart()
renju.restart()
renju.bind("<Button-1>",add_chessman)
#test
if (chessboard.count)==0:
renju.bind("<Button-1>",add_chessman)
renju.master.mainloop()
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!