一.本案例基于UDP的socket编程方法来制作五子棋程序,网络五子棋采用C/S架构,分为服务器端和客户端,游戏时服务端首先启动,当客户端启动连接后,服务器端可以走棋,轮到自己棋才可以在棋盘上落子,同时下方标签会显示对方走起信息,服务器端用户可以通过“退出游戏”按钮可以结束游戏;
1.数据通信协议
网络五子棋游戏设计的难点在于对方进行通信,这里使用面向非连接的Socket编程,Socket编程用于C/S开发,在这类应用中,客户端和服务器端通常需要先建立连接,然后发送和接收数据,交互完成后需要断开连接,本章采用基于UDP的Socket编程实现,这里虽然两台计算机不分主次,但涉及时候假设一台作为服务器端,等待其他方加入,其他想加入必须输入服务器端主机的IP;
下面展示一些 数据通信协议代码。
def receiveMessage(): global s while True: global addr data,addr=s.recvfrom(1024) data=data.decode(\'utf-8\') a=data.split(\"|\") if not data: print(\"client has exited!\") break elif a[0]==\'join\': #连接服务器请求 print(\'client 连接服务器!\') label1[\"text\"]=\'client连接服务器成功,请你走棋!\' elif a[0]==\'exit\': print(\'client 对方退出!\') label1[\"text\"]=\'client对方退出,游戏结束!\' elif a[0]==\'over\': print(\'对方赢信息!\') label1[\"text\"]=data.split(\"|\")[0] showinfo(title=\"提示\",message=data.split(\"|\")[1]) elif a[0]==\'move\': print(\'received:\',data,\'from\',addr) p=a[1].split(\",\") x=int(p[0]) y=int(p[1]) print(p[0],p[1]) label1[\"text\"]=\"客户端走的位置\"+p[0]+p[1] drawOtherChess(x,y) s.close()
2.判断输赢的算法
本游戏关键技术就是判断输赢的算法,对于算法实现大致可以分为以下几个部分:
(1)判断X=Y轴上是否形成五子连珠;
(2)判断X=-Y轴上是否形成五子连珠;
(3)判断X轴上是否形成五子连珠;
(4)判断Y轴上是否形成五子连珠;
#输赢判断 def win_lose(): a=str(turn) print(\"a=\",a) for i in range(0,11): for j in range(0,11): if map[i][j]==a and map[i+1][j+1]==a and map[i+2][j+2]==a and map[i+3][j+3]==a and map[i+4][j+4]==a: print(\"x=y轴上形成五子连珠\") return True for i in range(4,15): for j in range(0,11): if map[i][j]==a and map[i-1][j+1]==a and map[i-2][j+2]==a and map[i-3][j+3]==a and map[i-4][j+4]==a: print(\"x=-y轴上形成五子连珠\") return True for i in range(0,15): for j in range(4,15): if map[i][j]==a and map[i][j-1]==a and map[i][j-2]==a and map[i][j-2]==a and map[i][j-4]==a: print(\"Y轴上形成了五子连珠\") return True for i in range(0,11): for j in range(0,15): if map[i][j]==a and map[i+1][j]==a and map[i+2][j]==a and map[i+3][j]==a and map[i+4][j]==a: print(\"X轴形成五子连珠\") return True return False
二. 源代码:
1.客户端编程代码如下:
from tkinter import * from tkinter.messagebox import * import socket import threading import os #主程序 root=Tk() root.title(\"网络五子棋v2.0--UDP客户端\") imgs=[PhotoImage(file=\'E:\\\\game\\\\BlackStone.gif\'),PhotoImage(file=\'E:\\\\game\\\\WhiteStone.gif\')] turn=0 Myturn=-1 #画对方棋子 def drawOtherChess(x,y): global turn img1=imgs[turn] cv.create_image((x*40+20,y*40+20),image=img1) cv.pack() map[x][y]=str(turn) #换下一方走棋 if turn==0: turn=1 else: turn=0 #发送消息 def sendMessage(pos): global s s.sendto(pos.encode(),(host,port)) #退出函数 def callexit(event): pos=\"exit|\" sendMessage(pos) os._exit(0) #走棋函数 def callback(event): global turn global Myturn if Myturn==-1: Myturn=turn else: if(Myturn!=turn): showinfo(title=\"提示\",message=\"还没轮到自己走棋\") return #print(\"clicked at\",event.x,event.y) x=(event.x)//40 y=(event.y)//40 print(\"clicked at\",x,y,turn) if map[x][y]!=\" \": showinfo(title=\"提示\",message=\"已有棋子\") else: img1=imgs[turn] cv.create_image((x*40+20,y*40+20),image=img1) cv.pack() map[x][y]=str(turn) pos=str(x)+\',\'+str(y) sendMessage(\"move|\"+pos) print(\"客户端走的位置\",pos) label1[\"text\"]=\"客户端走的位置\"+pos #输出输赢信息 if win_lose( )==True: if turn==0: showinfo(title=\"提示\",message=\"黑方你赢了\") sendMessage(\"over|黑方你赢了!\") else: showinfo(title=\"提示\",message=\"白方你赢了!\") sendMessage(\"over|白方你赢了!\") #换下一方走棋: if turn==0: turn=1 else: turn=0 #画棋盘 def drawQiPan( ): #画棋盘 for i in range(0,15): cv.create_line(20,20+40*i,580,20+40*i,width=2) for i in range(0,15): cv.create_line(20+40*i,20,20+40*i,580,width=2) cv.pack() #输赢判断 def win_lose(): a=str(turn) print(\"a=\",a) for i in range(0,11): for j in range(0,11): if map[i][j]==a and map[i+1][j+1]==a and map[i+2][j+2]==a and map[i+3][j+3]==a and map[i+4][j+4]==a: print(\"x=y轴上形成五子连珠\") return True for i in range(4,15): for j in range(0,11): if map[i][j]==a and map[i-1][j+1]==a and map[i-2][j+2]==a and map[i-3][j+3]==a and map[i-4][j+4]==a: print(\"x=-y轴上形成五子连珠\") return True for i in range(0,15): for j in range(4,15): if map[i][j]==a and map[i][j-1]==a and map[i][j-2]==a and map[i][j-2]==a and map[i][j-4]==a: print(\"Y轴上形成了五子连珠\") return True for i in range(0,11): for j in range(0,15): if map[i][j]==a and map[i+1][j]==a and map[i+2][j]==a and map[i+3][j]==a and map[i+4][j]==a: print(\"X轴形成五子连珠\") return True return False #接受消息 def receiveMessage(): #接受消息 global s while True: data = s.recv(1024).decode(\'utf-8\') a = data.split(\"|\") if not data: print(\'server has exited!\') break elif a[0] == \'exit\': print(\'对方退出!\') lanel1[\"text\"] = \'对方退出!游戏结束!\' elif a[0] == \'over\': print(\'对方赢信息!\') label1[\"text\"] = data.split(\"|\")[0] showinfo(title=\"提示\", message=data.split(\"|\")[1]) elif a[0] == \'move\': print(\'received:\', data) p = a[1].split(\",\") x = int(p[0]) y = int(p[1]) print(p[0], p[1]) label1[\"text\"] = \"服务器走的位置\" + p[0] + p[1] drawOtherChess(x,y) s.close() #启动线程接受客户端消息 def startNewThread(): thread=threading.Thread(target=receiveMessage,args=()) thread.setDaemon(True) thread.start() #主程序 map=[[\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \"] for y in range(15)] cv=Canvas(root,bg=\'green\',width=610,height=610) drawQiPan() cv.bind(\"<Button-1>\",callback) cv.pack() label1=Label(root,text=\"客户端...\") label1.pack() button1=Button(root,text=\"退出游戏\") button1.bind(\"<Button-1>\",callexit) button1.pack() #创建UDP s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) port=8000 host=\'localhost\' pos=\'join|\' sendMessage(pos) startNewThread() root.mainloop()
2.数据通信协议源代码:
下面展示一些 数据通信协议源代码。
def receiveMessage(): global s while True: global addr data,addr=s.recvfrom(1024) data=data.decode(\'utf-8\') a=data.split(\"|\") if not data: print(\"client has exited!\") break elif a[0]==\'join\': #连接服务器请求 print(\'client 连接服务器!\') label1[\"text\"]=\'client连接服务器成功,请你走棋!\' elif a[0]==\'exit\': print(\'client 对方退出!\') label1[\"text\"]=\'client对方退出,游戏结束!\' elif a[0]==\'over\': print(\'对方赢信息!\') label1[\"text\"]=data.split(\"|\")[0] showinfo(title=\"提示\",message=data.split(\"|\")[1]) elif a[0]==\'move\': print(\'received:\',data,\'from\',addr) p=a[1].split(\",\") x=int(p[0]) y=int(p[1]) print(p[0],p[1]) label1[\"text\"]=\"客户端走的位置\"+p[0]+p[1] drawOtherChess(x,y) s.close() #输赢判断 def win_lose(): a=str(turn) print(\"a=\",a) for i in range(0,11): for j in range(0,11): if map[i][j]==a and map[i+1][j+1]==a and map[i+2][j+2]==a and map[i+3][j+3]==a and map[i+4][j+4]==a: print(\"x=y轴上形成五子连珠\") return True for i in range(4,15): for j in range(0,11): if map[i][j]==a and map[i-1][j+1]==a and map[i-2][j+2]==a and map[i-3][j+3]==a and map[i-4][j+4]==a: print(\"x=-y轴上形成五子连珠\") return True for i in range(0,15): for j in range(4,15): if map[i][j]==a and map[i][j-1]==a and map[i][j-2]==a and map[i][j-2]==a and map[i][j-4]==a: print(\"Y轴上形成了五子连珠\") return True for i in range(0,11): for j in range(0,15): if map[i][j]==a and map[i+1][j]==a and map[i+2][j]==a and map[i+3][j]==a and map[i+4][j]==a: print(\"X轴形成五子连珠\") return True return False def checkwin(x,y): flag=False count=1 color=map[x][y] i=1 #横向判断 while color==map[x+i][y]: count=count+1 i=i+1 i=1 while color==map[x-i][y]: count=count+1 i=i+1 if count>=5: flag=True #竖向判断 i=1 while color==map[x][y+i]: count=count+1 i=i+1 i=1 while color==map[x][y-i]: count=count+1 i=i+1 if count>=5: flag=True #x=y判断 i=1 j=1 while color==map[x+i][y+i]: count=count+1 i=i+1 j=j+1 if count>=5: flag=True j=1 i=1 while color==map[x-i][y-i]: count=count+1 i=i+1 j=j+1 if count>=5: flag=True
3.服务器端源代码
客户端源代码如下:
from tkinter import * from tkinter.messagebox import * import socket,threading,os def drawQiPan(): for i in range(0,15): cv.create_line(20,20+40*i,580,20+40*i,width=2) for i in range(0,15): cv.create_line(20+40*i,20,20+40*i,580,width=2) cv.pack() #走棋函数 def callpos(event): global turn global Myturn if Myturn==-1: #第一次确认自己的角色 Myturn=turn else: if(Myturn!=turn): showinfo(title=\"提示\",message=\"还没轮到自己下棋\") return #print(\"clicked at\",event.x,event.y,true) x=(event.x)//40 y=(event.y)//40 print(\"clicked at\",x,y,turn) if map[x][y]!=\" \": showinfo(title=\"提示\",message=\"已有棋子\") else: img1=imgs[turn] cv.create_image((x*40+20,y*40+20),image=img1) cv.pack() map[x][y]=str(turn) pos=str(x)+\",\"+str(y) sendMessage(\"move|\"+pos) print(\"服务器走的位置\",pos) label1[\"text\"]=\"服务器走的位置\"+pos #输出输赢信息 if win_lose( )==True: if turn==0: showinfo(title=\"提示\",message=\"黑方你赢了\") sendMessage(\"over|黑方你赢了\") else: showinfo(title=\"提示\", message=\"白方你赢了\") sendMessage(\"over|白方你赢了\") #换下一方走棋 if turn==0: turn=1 else: turn=0 #发送消息 def sendMessage(pos): global s global addr s.sendto(pos.encode(),addr) #退出函数 def callexit(event): pos=\"exit|\" sendMessage(pos) os._exit(0) #画对方棋子 def drawOtherChess(x,y): global turn img1=imgs[turn] cv.create_image((x*40+20,y*40+20),image=img1) cv.pack() map[x][y]=str(turn) #换下一方走棋 if turn==0: turn=1 else: turn=0 #判断整个棋盘的输赢 def win_lose(): a=str(turn) print(\"a=\",a) for i in range(0,11): for j in range(0,11): if map[i][j]==a and map[i+1][j+1]==a and map[i+2][j+2]==a and map[i+3][j+3]==a and map[i+4][j+4]==a: print(\"x=y轴上形成五子连珠\") return True for i in range(4,15): for j in range(0,11): if map[i][j]==a and map[i-1][j+1]==a and map[i-2][j+2]==a and map[i-3][j+3]==a and map[i-4][j+4]==a: print(\"x=-y轴上形成五子连珠\") return True for i in range(0,15): for j in range(4,15): if map[i][j]==a and map[i][j-1]==a and map[i][j-2]==a and map[i][j-2]==a and map[i][j-4]==a: print(\"Y轴上形成了五子连珠\") return True for i in range(0,11): for j in range(0,15): if map[i][j]==a and map[i+1][j]==a and map[i+2][j]==a and map[i+3][j]==a and map[i+4][j]==a: print(\"X轴形成五子连珠\") return True return False #输出map地图 def print_map(): for j in range(0,15): for i in range(0,15): print(map[i][j],end=\' \') print(\'w\') #接受消息 def receiveMessage(): global s while True:#接受客户端发送的消息 global addr data,addr=s.recvfrom(1024) data=data.decode(\'utf-8\') a=data.split(\"|\") if not data: print(\'client has exited!\') break elif a[0]==\'join\':#连接服务器的请求 print(\'client 连接服务器!\') label1[\"text\"]=\'client连接服务器成功,请你走棋!\' elif a[0]==\'exit\': print(\'client对方退出!\') label1[\"text\"]=\'client对方退出,游戏结束!\' elif a[0]==\'over\': print(\'对方赢信息!\') labl1[\"text\"]==data.split(\"|\")[0] showinfo(title=\"提示\",message=data.split(\"1\")[1]) elif a[0]==\'move\': print(\'received:\',data,\'from\',addr) p=a[1].split(\",\") x=int(p[0]) y=int(p[1]) print(p[0],p[1]) label1[\"text\"]=\"客户端走的位置\"+p[0]+p[1] drawOtherChess(x,y) s.close() def startNewThread( ):#启动新线程来接受客户端消息 thread=threading.Thread(target=receiveMessage,args=()) thread.setDaemon(True) thread.start() root=Tk() root.title(\"网络五子棋v2.0-服务器端\") imgs=[PhotoImage(file=\'E:\\\\game\\\\BlackStone.gif\'),PhotoImage(file=\'E:\\\\game\\\\WhiteStone.gif\')] turn=0 Myturn=-1 map=[[\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \",\" \"] for y in range(15)] cv=Canvas(root,bg=\'green\',width=610,height=610) drawQiPan() cv.bind(\"<Button-1>\",callpos) cv.pack() label1=Label(root,text=\"服务器端...\") label1.pack() button1=Button(root,text=\"退出游戏\") button1.bind(\"<Button-1>\",callexit) button1.pack() #创建UDP SOCKET s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind((\'localhost\',8000)) addr=(\'localhost\',8000) startNewThread() root.mainloop()
运行结果展示:
所有的都在这里了。
更多有趣的经典小游戏实现专题,也分享给大家:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。