python实现网页多人对战版五子棋(websocket)

联网版五子棋

前个星期websocket做了一个联机版五子棋,一路坑坑洼洼没有搞清楚原理就开始写,饶了好多弯路。现在完工了腾出时间来整理的同时再对websocket做一些总结,同时对那些边边角角的知识做记录。

能够异步通信,首先想到的当然是http轮询,但是学长要求用websocket实现,所以也没多想就用websocket呗,反正都是从0开始。

( 使用的是 < Sanic + websocket > )

Blueprint:
	Gobang
	  |
	  |—— mysql		
  	  |    |—— __init__.py
	  |	   |—— config.py		# 数据库配置文件
	  |	   |—— create_table_ifnot.py	# 建表文件
	  |	   |—— DB_api.py	# 数据库接口
	  |—— play		# 判断输赢	
	  |	   |—— __init__.py
	  |	   |—— battle.py
	  |—— view
	  |	   |—— __init.py
	  |	   |—— conn.py	# 与前端的接口
	  |	   |—— conf.py	# 配置文件
	  |—— test.py	# 测试接口用
	  |—— usr.py	# 主程序入口
	 
< usr. py >

在与前端测试的过程中发生了跨域问题,网上找了一种简单的办法,但仍不理解其原理。
关于跨域问题的理解(但是现在还没写,只有百度)

from sanic import Sanic, response
import asyncio

from view.conn import bp1


app = Sanic(__name__)
app.blueprint(bp1)


@app.route('/test')
async def test(request):
    return response.text('success')


@app.middleware('response')		# 添加即可解决跨域问题
async def add(request, response):
    response.headers["Access-Control-Allow-Origin"] = '*'
    response.headers["Access-Control-Allow-Methods"] = "POST,GET,OPTIONS"
    response.headers["Access-Control-Expose-Headers"] = "Set-Cookie,token"
    response.headers["Access-Control-Allow-Headsanic_demo/main/usr.py:16ers"] = "Set-Cookie,token"
    response.headers["Access-Control-Allow-Credentials"] = "true"


if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port=9001)
    
< conf. py >
battleground = {}    # 存放正在对战的双方名字-->you:oppo

battledic = {}   # 存放参加战斗的玩家名字-->ip:name
battle_wsdic = {}   # battle的ws字典-->ip:ws
waitdic = {}   # 存放闲置玩家名字-->ip:name
online_wsdic = {}     # ws列表-->ip:ws

aside_quit = 0  # 一方退出而另一方仍在游戏中的情况

< conn. py>

这里是这个项目的核心:对各个用户做分类,其中列表(字典)的处理尤为重要

设计的是两个状态:等待和对战

进入
主动选择
被动传唤
用户
注册
等待池
主动方
被动方
对战
from sanic import Blueprint

from view.conf import battledic, battleground, battle_wsdic, \
                        online_wsdic, waitdic
from play.battle import *
from mysql.DB_api import db_insert


bp1 = Blueprint('bp1')
battlinglist = {}  # bothside:battledata


@bp1.websocket('/register')
async def register(request, ws):
    _quit = 0
    ip = request.ip
    try:
        waitdic.pop(ip)
    except:
        pass
    while True:
        print('返回register')
        name = await ws.recv()
        _namelist = []
        for key, value in waitdic.items():
            _namelist.append(value)
        if _namelist.count(name) == 0 and name != 'null' and name:
            ip = request.ip
            waitdic[ip] = name      # ip-名字
            await ws.send('positive')
            print('your name:', name)
            print('waitdic:', waitdic)
        else:
            await ws.send('negative')
            print('<<<<<<<<<<<<<<<<<输入的名字不合理')

        if _quit == 1:
            break


@bp1.websocket('/waiting')
async def waiting(request, ws):
    your_ip = request.ip
    try:
        name = waitdic[your_ip]     # <<<<<<<<<<<<<<<<<<<<手机解锁唤醒的时候会有进入waiting的操作,如果waitdic中没有这个ip就会报错
        try:    # 获得这个人的在play里面的旧名字
            oldname = battledic[your_ip]
            print('一边重置')
            print('旧名字:', oldname)
        except:
            pass
        _namelist = []

        for value in waitdic.values():
            _namelist.append(value)
        if _namelist.count(name) == 1 and name != 'null' and name:
            online_wsdic[your_ip] = ws  # 将ip与ws绑定

            # 给所有人广播名单
            await  broadcast_all()
            quit_ = 0
            _oldrt = None
            wait = 0
            while True:
                _blackgoin = 0
                _whitegoin = 0
                _blackquit = 0
                _whitequit = 0

                for black, white in battleground.items():
                    if black == name:
                        _oldrt = None
                        _blackgoin = 1
                        battledic[your_ip] = name
                        await ws.send('yes')
                    if white == name:
                        _oldrt = None
                        _whitegoin = 1
                        battledic[your_ip] = name
                        await ws.send('yes')

                # 开始play后等待状态睡眠,双方
                if _blackgoin == 1:
                    while True:
                        if your_ip not in battledic:
                            _blackquit = 1
                        if _blackquit == 1:
                            await  broadcast_all()  # 给所有人广播名单
                            break   # 如果从play中退出来则break
                        await asyncio.sleep(1)
                if _whitegoin == 1:
                    while True:
                        if your_ip not in battledic:
                            _whitequit = 1
                        if _whitequit == 1:
                            await  broadcast_all()  # 给所有人广播名单
                            break
                        await asyncio.sleep(1)

                if quit_ == 1:      # 暂定永久等待
                    break
                if wait == 10:
                    wait = 0    # wait用于控制台显示频率用
                    print(name, '正在等待')
                wait += 1
                await asyncio.sleep(0.3)        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<调整延迟时间以快速开始游戏
        else:
            print(name, '名字错误!!!')

    except KeyError:
        print('<<<<<<<<<<<<这个ip不存在')
    finally:
        try:
            online_wsdic.pop(your_ip)
            while True:
                _quit = 0
                if your_ip in waitdic:
                    _quit = 1
                if _quit == 1:
                    break
                await asyncio.sleep(0.1)
            waitdic.pop(your_ip)
            # 给所有人广播名单
            await  broadcast_all()

        except KeyError:
            print('<<<<<<<<<<<<这个ip不存在')


@bp1.websocket('/choose')
async def choose(request, ws):
    _list = []   # 制作等待列表
    ip_black = 0
    ip_white = 0
    black = await ws.recv()  # 接收当前用户
    white = await ws.recv()  # 接收他选择的对手

    for i, j in waitdic.items():  # for循环里最好用i, j
        _list.append(j)
        if black == j:
            ip_black = i
        if white == j:
            ip_white = i
    if _list.count(white) == 1 and _list.count(black) == 1 and white != 'null' and white and white != black:
        # 如果对方在等待列表里
        # 如果对手是存在的
        # 如果对手不是自己
        # 则绑定战斗双方

        await online_wsdic[ip_white].send('confirm')
        answer = await online_wsdic[ip_white].recv()
        if answer == 'yes':
            await online_wsdic[ip_black].send('pass')
            await online_wsdic[ip_white].send('pass')
            battleground[black] = white
        elif answer == 'no':
            await online_wsdic[ip_black].send('nopass')
            await online_wsdic[ip_white].send('nopass')
        else:
            print(1111)
    else:
        print(black)
        print(white)
        print('<--你的选择有问题')


@bp1.websocket('/play')
async def play(request, ws):
    flag_black = False
    flag_white = False
    _onlyOnce_b = 0
    _onlyOnce_w = 0
    black = None
    ip_black = None
    white = None
    ip_white = None
    bothside = None
    Tom = None
    Jerry = None
    try:
        endbattle = -1
        your_ip = request.ip
        your_name = battledic[your_ip]
        battle_wsdic[your_ip] = ws     # 把当前用户ws添加进来

        # 获取双方的名字
        for key, value in battleground.items():
            if your_name == key or your_name == value:
                black = key     # 根据battledic获得双方的名字, black是主动点击方
                white = value

        bothside = black + white
        battlinglist[bothside] = []
        # 开始下棋前的确认等待(添加等待)
        while True:
            for i, j in battle_wsdic.items():
                if battledic[i] == black and _onlyOnce_b == 0:
                    flag_black = True
                    _onlyOnce_b = 1
                if battledic[i] == white and _onlyOnce_w == 0:
                    flag_white = True
                    _onlyOnce_w = 1

            if flag_white and flag_black:
                print(your_name, '可以开始了')
                break
            else:
                print(your_name, '在等待对手确认')
            await asyncio.sleep(0.3)        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<调整延迟时间以快速开始游戏
        # 获得双方的ip,这部分只能放在添加等待的后面
        for i, j in battledic.items():
            if j == white:  # 根据battlelist获得双方的ip
                ip_white = i
            if j == black:
                ip_black = i

        # 将这个人从waitlist去除并广播
        waitdic.pop(your_ip)
        await broadcast_all()

        # 下棋部分
        Tom = battle_wsdic[ip_black]    # 获得双方的ws对象
        Jerry = battle_wsdic[ip_white]
        while True:
            # tom先下棋
            rec_t = await Tom.recv()
            tom_play = dumps(rec_t)
            if tom_play:
                print(black + ' 下棋', ':', tom_play)
                battlinglist[bothside].append(tom_play)  # 存放有效数据
                endbattle = check_win(tom_play, battlinglist[bothside])  # 判断tom这一步棋赢了没
                await Jerry.send(rec_t)  # 传给jerry 前端传过来的数据,是str型
            # ******************黑方获胜*****************
            if endbattle == 1:
                print('黑色方' + black + '获胜')
                print('战斗数据:', battlinglist[bothside])
                db_insert(locations=battlinglist[bothside], win=endbattle)    # 向数据库中写入该盘对句
                break

            # jerry下棋
            rec_j = await Jerry.recv()
            jerry_play = dumps(rec_j)
            if jerry_play:
                print(white + ' 下棋', ':', jerry_play)    # 显示这个人下的那个子
                battlinglist[bothside].append(jerry_play)
                endbattle = check_win(jerry_play, battlinglist[bothside])
                await Tom.send(rec_j)  # 传给Tom 前端传来的数据,是str型
            # ******************白方获胜*****************
            if endbattle == 0:
                print('白色方' + white + '获胜')
                print('战斗数据:', battlinglist[bothside])
                db_insert(locations=battlinglist[bothside], win=endbattle)    # 向数据库中写入该盘对句
                break
    finally:
        try:
            battleground.pop(black)    # 战斗列表去出这两个人
            battlinglist.pop(bothside)  # 将这一盘的战斗数据清除
            battledic.pop(ip_black)
            battledic.pop(ip_white)
            battle_wsdic.pop(ip_black)
            battle_wsdic.pop(ip_white)
            waitdic[ip_black] = black
            waitdic[ip_white] = white
        except KeyError:
            print('<<<<<<<<<<<<<<<battleground错误')
        await Tom.send('battle complete!')
        await Jerry.send('battle complete!')


async def broadcast_all():
    broadlist = []
    for i, j in waitdic.items():
        broadlist.append(j)
    rt = ','.join(str(i) for i in broadlist)  # 将数组转换成字符串发送
    for i in online_wsdic.values():  # 给所有用户同时更新用户信息界面
        try:  # 加一个try于是不阻塞了~~
            await i.send(rt)
        except:
            print('<<<<<<<<<<<<<<<rt部分出错')
            continue
<battle. py>

五子棋的判断输赢部分

def dumps(_str):
    # 将前端发过来的str转换成list
    _list = _str.join(',0')
    k = _list[2: -2].split(',')

    rt = []
    for i in range(len(k)):
        rt.append(int(k[i]))
    return rt

# 判断这颗棋子有没有赢
def check_win(data, battlinglist):
    print(battlinglist)

    z1 = []     # -方向棋子
    z2 = []     # |方向棋子
    z3 = []     # /方向棋子
    z4 = []     # \方向棋子
    flag = False    # 5连标志符

    color = data[2]     # 取出颜色
    x = data[0]     # 取出x
    y = data[1]     # 取出y

    for i in battlinglist:
        xi = i[0]   # 取出循环的x
        yi = i[1]   # 取出循环的y
        colori = i[2]

        # 只判断相同颜色
        if colori != color:
            continue
        if x == xi:		# |
            z1.append(yi)
            flag = check_five(z1)
            if flag:
                print('z1:', z1)
                break
        if y == yi:		# ——
            z2.append(xi)
            flag = check_five(z2)
            if flag:
                print('z2:', z2)
                break
        if xi - x == yi - y:	# /
            z3.append(xi)
            flag = check_five(z3)
            if flag:
                print('z3:', z3)
                break
        if xi - x == y - yi:	# \
            z4.append(xi)
            flag = check_five(z4)
            if flag:
                print('z4:', z4)
                break
        else:
            continue

    if flag:
        return color
    else:
        return -1

# 判断5连
def check_five(list1):
    list1.sort()
    count_one = []
    counter = []
    rt = False
    mm = 0

    for i in list1:
        if i == list1[0]:
            mm = i
            continue
        count_one.append(i - mm)
        mm = i

    # print(count_one)
    for i in range(len(count_one)-3):
        counter = count_one[i:i + 4]
        if counter.count(1) == 4:
            print('5连')
            rt = True

    return rt

写这个demo的时候大部分时间都是在写conn. py,虽然看似逻辑简单,但是其中的大大小小的坑真的是无数。

希望自己日后能在总体布局和代码质量上有所突破

实现PythonWebSocket多人聊天自动化测试,可以采用以下步骤: 1. 安装所需的库:首先需要安装WebSocket相关的库,如websocket-client、selenium等,可以通过pip命令进行安装。 2. 创建WebSocket连接:使用websocket-client库创建WebSocket连接,指定服务器的地址和端口号。可以使用下面的代码实现: ```python import websocket def on_message(ws, message): # 处理收到的消息 print(message) def on_error(ws, error): # 处理错误信息 print(error) def on_close(ws): # 关闭WebSocket连接 print("Connection closed") def on_open(ws): # 连接成功后的处理 pass if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("ws://localhost:8080/chat", on_message=on_message, on_error=on_error, on_close=on_close) ws.on_open = on_open ws.run_forever() ``` 3. 发送和接收消息:在on_open函数中可以发送消息到服务器,使用ws.send()方法发送消息。在on_message函数中处理收到的消息。 4. 编写测试用例:根据需求编写相应的测试用例,包括发送消息、接收消息、断开连接等场景,使用selenium或其他相关库模拟多个WebSocket客户端。 5. 执行测试用例:使用unittest或pytest等测试框架来管理和执行测试用例,可以编写测试套件,在其中执行各个测试用例。 6. 分析结果和报告:根据测试结果进行分析,生成测试报告,查找问题并进行修复。 以上是实现PythonWebSocket多人聊天自动化测试的基本步骤,具体实现可以根据具体需求和场景进行调整和扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值