本案例基于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("",callback)

cv.pack()

label1=Label(root,text="客户端...")

label1.pack()

button1=Button(root,text="退出游戏")

button1.bind("",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.服务器端源代码

客户端源代码如下:

1

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')

接受消息

亨达代理申请http://www.kaifx.cn/broker/ha...

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("",callpos)

cv.pack()

label1=Label(root,text="服务器端...")

label1.pack()

button1=Button(root,text="退出游戏")

button1.bind("",callexit)

button1.pack()

创建UDP SOCKET

s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

s.bind(('localhost',8000))

addr=('localhost',8000)

startNewThread()

root.mainloop()


zhuanzhudeyipi
65 声望2 粉丝