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