14 网络通信案例——基于UDP的网络五子棋游戏(2)

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)]
# print(map)

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)
    
    # 判断X=Y轴上是否形成五子连珠
    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
    
    # 判断X=-Y轴上是否形成五子连珠
    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
    
    # 判断Y轴上是否形成五子连珠
    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
    
    # 判断X轴上是否形成五子连珠
    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)]
# print(map)

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)
    
    # 判断X=Y轴上是否形成五子连珠
    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
    
    # 判断X=-Y轴上是否形成五子连珠
    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
    
    # 判断Y轴上是否形成五子连珠
    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
    
    # 判断X轴上是否形成五子连珠
    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()
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值