14.4 程序源码
1、服务器端程序设计的步骤
from tkinter import *
from tkinter. messagebox import *
import socket
import threading
import os
主程序
root = Tk( )
root. title( '网络五子棋v2.0——服务器端' )
imgs = [ PhotoImage( file = 'BlackStone.gif' ) , PhotoImage( file = 'WhiteStone.gif' ) ]
turn = 0
Myturn = - 1
map = [ [ ' ' ] * 15 for y in range ( 15 ) ]
cv = Canvas( root, bg = 'green' , width = 610 , heigth = 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( )
receiveMessage( )
root. mainloop( )
退出函数
def callexit ( event) :
pos = 'exit|'
sendMessage( pos)
os. _exit( 0 )
走棋函数
def callpos ( event) :
global turn
global Myturn
if Myturn == - 1 :
Myturn = turn
else :
if Myturn != turn:
showinfo( title = '提示' , message= '还没轮到自己走棋' )
return
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 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 drawQiPan ( ) :
for i in range ( 15 ) :
cv. create_line( 20 , 20 + 40 * i, 580 , 20 + 40 * i, width = 2 )
for i in range ( 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 ( 11 ) :
for j in range ( 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 ( 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 ( 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- 3 ] == a and map [ i] [ j- 4 ] == a:
print ( 'Y轴上形成五子连珠!' )
return True
for i in range ( 11 ) :
for j in range ( 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 ( 15 ) :
for i in range ( 15 ) :
print ( map [ i] [ j] , end = ' ' )
print ( 'w' )
处理接收消息data
通信协议具体实现
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 ( 'receive:' , 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 sendMessage ( pos) :
global s
global addr
s. sendto( pos. encode( ) , addr)
启动线程接收客户端的消息
def startNewThread ( ) :
thread = threading. Thread( target= receiveMessage, args = ( ) )
thread. setDaemon( True )
thread. start( )
2、客户端程序设计的步骤
from tkinter import *
from tkinter. messagebox import *
import socket
import threading
import os
主程序
root = Tk( )
root. title( '网络五子棋v2.0——UDP客户端' )
imgs = [ PhotoImage( file = 'BlackStone.gif' ) , PhotoImage( file = 'WhiteStone.gif' ) ]
turn = 0
Myturn = - 1
map = [ [ ' ' ] * 15 for y in range ( 15 ) ]
cv = Canvas( root, bg = 'green' , width = 610 , heigth = 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)
port = 8000
host = 'localhost'
post = 'join|'
sendMessage( pos)
startNewThread( )
receiveMessage( )
root. mainloop( )
退出函数
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
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 ( 15 ) :
cv. create_line( 20 , 20 + 40 * i, 580 , 20 + 40 * i, width = 2 )
for i in range ( 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 ( 11 ) :
for j in range ( 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 ( 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 ( 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- 3 ] == a and map [ i] [ j- 4 ] == a:
print ( 'Y轴上形成五子连珠!' )
return True
for i in range ( 11 ) :
for j in range ( 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
接收消息
处理接收消息data
通信协议具体实现
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 ( '对方退出!' )
label1[ 'text' ] = '对方退出,游戏结束!'
elif a[ 0 ] == 'over' :
print ( '对方赢信息!' )
label1[ 'text' ] = data. split( '|' ) [ 0 ]
showinfo( title= '提示' , message= data. split( '|' ) [ 1 ] )
elif a[ 0 ] == 'move' :
print ( 'receive:' , 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 sendMessage ( pos) :
global s
s. sendto( pos. encode( ) , ( host, port) )
启动线程接收服务器端的消息
def startNewThread ( ) :
thread = threading. Thread( target= receiveMessage, args = ( ) )
thread. setDaemon( True )
thread. start( )