zoukankan      html  css  js  c++  java
  • 庖丁解牛-小程序版好友对战答题项目实践(一)

                

            新的一年已经拉开了序幕,有的忙着离职、有的忙着请求加薪,有的忙着春运,有人忙着相亲。。

            对于绝大多数人来说,新的一年就是新的开始,新的开始也就是雄心壮志立flag的之时,只求不恍惚间到年尾,然后再把去年的flag,copy一次。

            千里之行,始于足下。所以,我的雄心壮志,也从这简简单单的知识分享开始。

            说到知识分享,就不能不提去年年底大火的直播答题app,不过,随着时间的推移,貌似热度已渐减。作为一个不算资深的程序猿,当别人为了冲关成功而欣喜,为了失败而失落时,我觉得程序猿们应该有透过现象看本质的想法与能力,正如,不以物喜,不以己悲。

            废话不多少,好文刚出锅,大家趁热食用。

        

    01

            本次我分享的是小程序版好友对战答题的实现思路与具体方法,由于篇幅问题,我将分成多个小段进行分享。首先我们先来分析下需求流程。

        

            首先,用户进入小程序。有两个选择,一,发起挑战;二.围观对战,选择围观对战则随机进入一个正在对战的房间,成为围观观众。选择发起挑战,则服务端生成一个房间号,然后触发分享操作,携带生成的房间号,由用户选择分享给好友或者微信群。

            微信用户通过分享的卡片进入小程序后,可选择参战或者围观,如果已经选择参战了,则其他用户自动成为围观用户。此时,发起方的页面状态由等待好友响应变为等待开始。在发起方单击开始之前,参战的用户可选择退出参战,此时,任意一个围观用户则可以选择参战。

            答题正式开始时,每道题有10s的时间回答。答错,或者超时,均认为答题错误,则不加分。答对,则根据答题用时,(11-所用秒数)*10的公式进行加分,每题满分100(留了1s时间,用户客户端和服务端之间的通讯耗时,以及客户端渲染题目所需要的时间),最后一题双倍分数。

        

    02

            下面说下程序的实现逻辑:

        

            程序分为两部分,小程序端和服务端。为了满足答题的及时性以及用户体验,小程序与服务端间的通讯使用WebSocket。小程序端负责用户交互,展示返回的数据。

            服务端负责处理用户创建房间、进入房间、围观、发弹幕的操作。

    服务端的逻辑功能包括:处理围观用户的请求,围观用户的请求分为两种,随机围观和指定房间号围观,服务端根据用户请求数据中是否包含房间号进行判断,如果不含,则随机进入正在进行中的对战房间进行围观。

            处理围观用户发弹幕请求。用户在答题过程中,围观用户可进行交流评论,然后以弹幕的形式实时显示在界面中。

    处理用户发起挑战的请求。用户发起挑战,则生成一个房间号,存储在数据库,并返回给请求用户。

            处理应战用户请求。用户点击应战按钮后,设置当前房间状态为配对成功,其他用户则不能再发起此房间的挑战。

            处理放弃挑战请求。与应战操作逻辑相反。

            处理房主点击开始请求。房主点击开始后,服务端随机从数据库中抽取有效的题目。并每隔11s(考虑到客户端与服务端之间的通讯耗时和客户端页面渲染耗时),推送新的题目,直到答题完毕。

            处理用户提交答案请求。用户提交答案时,从数据库(或缓存)中匹配答案,正确时,则根据耗时,计算本轮分数,另外,需要将答题结果推送给围观用户。错误时,则将正确答案推送给答题者。

    处理用户超时未答。当服务端在11秒内未收到提交的答题请求,则自动判断答题超时,将正确答案推送给超时用户。

    03

    数据库中,跟题目相关的表有两个,一个是题库表,一个是每个对战房间的题目表。表结构如下:

    题库表:

    列名

    类型

    说明

    Id

    int

    主键,唯一标识

    CreateTime

    DateTime

    题目的创建时间

    Title

    Nvarchar

    标题

    Options

    Nvarchar

    答案选项

    Status

    int

    是否可用,默认1,可用。0为不可用

    Level

    int

    难易程度,值越大越难

     

     

     

     

     

     

     

     

     

     

     

    试卷表:

    列名

    类型

    说明

    Id

    int

    主键,唯一标识

    Title

    Nvarchar

    标题

    Options

    Nvarchar

    答案选项

    Answer

    int

    答案的序号。从1开始。

    Level

    int

    难易程度,值越大越难

    HomeId

    int

    房间号

    SubjectId

    int

    题库编号

            

     

     

     

     

     

     

     

     

     

     

     

     

    从上面的表中可以看出,题目的答案选项我是用nvarchar存储的,这样方便管理人员进行编辑。默认第一个为正确答案。所以,在从题库中抽取题目时,需要将答案顺序打乱,并记录正确答案的序号。

            具体实现思路是,首先随机从题库中抽取有效的题目存入临时表,然后遍历每条记录,把选项打乱顺序,并存入新表。最后删除临时表,将已选的题目的状态更新为不可用。代码如下:

     

    CREATE PROC [dbo].[proc_getsubject](@count INT,@homeId INT)
    
    AS
    
    BEGIN
    
    IF OBJECT_ID('tempdb..#Subject_TEMP','U') IS NOT NULL
    
    DROP TABLE #Subject_TEMP
    
    --随机从表中获取指定条数的有效题目,并存入临时表
    
    SELECT TOP (@count) Title,Options,Id,Level INTO #Subject_TEMP FROM dbo.Subject WHERE Status=1 ORDER BY NEWID()
    
    --删除试卷中,当前房间号已存在的题目
    
    DELETE [dbo].[ActivityItems] WHERE [HomeId]=@homeId
    
    --遍历每个题目
    
    WHILE @count>0
    
    BEGIN
    
    DECLARE @title NVARCHAR(500),@options NVARCHAR(2000),
    
    @level INT,--难易程度
    
    @newoptions NVARCHAR(2000),@id INT,@optionCount INT ,--当前答案的数量
    
    @answer INT--答案的索引,从1开始。
    
    SET @newoptions='' --初始化
    
    --从临时表中,取出一条数据
    
    SELECT TOP 1 @title=Title,@options=Options,@id=Id,@level=Level FROM #Subject_TEMP
    
    IF OBJECT_ID('tempdb..#Options_TEMP','U') IS NOT NULL
    
    DROP TABLE #Options_TEMP
    
    --使用表值函数,分割答案选项,并打乱顺序。
    
    SELECT * INTO #Options_TEMP FROM dbo.F_SplitSTR(@options,',')
    
    --获取选项的数量
    
    SELECT @optionCount=COUNT(1) FROM #Options_TEMP
    
    DECLARE @temp_i INT--循环里的索引
    
    SET @temp_i =1
    
    --循环分割后的答案,拼接成新的答案选项字符串
    
    WHILE @optionCount>0
    
    BEGIN
    
    DECLARE @item NVARCHAR(200),@sort INT
    
    --随机从答案选项中选择
    
    SELECT TOP 1 @item=col,@sort=sort FROM #Options_TEMP ORDER BY NEWID()
    
    SET @newoptions+=@item+','
    
    IF @sort=1
    
    SET @answer=@temp_i
    
    SET @optionCount-=1
    
    SET @temp_i+=1
    
    DELETE #Options_TEMP WHERE sort=@sort
    
    END
    
    SET @count-=1
    
    --从临时表中删除刚刚处理过的题目
    
    DELETE #Subject_TEMP WHERE Id=@id
    
    --将处理后的题目信息存入试卷表
    
    PRINT(@newoptions)
    
    INSERT [dbo].[ActivityItems] VALUES(@title,@newoptions,@answer,@level,@HomeId,@id)
    
    END
    
    /*更新已选题库为无效状态,保证每道题只出现1次,测试时,可不执行此代码。这样题目是可以重复利用的*/
    
    --UPDATE dbo.Subject SET Status=0 WHERE Id IN (SELECT SubjectId FROM [ActivityItems] WHERE HomeId=@homeId)
    
    SELECT * FROM ActivityItems WHERE HomeId=@homeId ORDER BY [Level]
    
    END

     

     

    其中,用于分割选项的方法代码如下:

    CREATE FUNCTION [dbo].[f_splitSTR](
    
    @s VARCHAR(8000), --待分拆的字符串
    
    @split VARCHAR(10) --数据分隔符
    
    )RETURNS @re TABLE(col VARCHAR(100),sort INT)
    
    AS
    
    BEGIN
    
    DECLARE @splitlen INT,@sort INT
    
    SET @sort=0
    
    SET @splitlen=LEN(@split+'a')-2
    
    WHILE CHARINDEX(@split,@s)>0
    
    BEGIN
    
    SET @sort+=1
    
    INSERT @re VALUES(LEFT(@s,CHARINDEX(@split,@s)-1),@sort)
    
    SET @s=STUFF(@s,1,CHARINDEX(@split,@s)+@splitlen,'')
    
    END
    
    INSERT @re VALUES(@s,@sort+1)
    
    RETURN
    
    END
    
     

    未完待续

    是不是有种戛然而止的感觉,没错,后面的正在整理中,整个系列将完整实现一个对战答题的小程序,包含服务端和小程序端的代码实现,以及服务端wss的开发与配置。

    欲知后事如何,倾听下回分解。

    本文首发公众号:微兔码农说,欢迎关注,分享。

     

     

    有的朋友要源码。所有的源码在整个系列发布完成后,会打包,供大家下载。如需文章中提到的数据库文件,请扫描下方二维码,关注微信公众号,回复答题数据库,即可获取数据库地址。

     

     

     

     

  • 相关阅读:
    yii AR 模式操作
    sql 注入命令大全
    PHP 防xss攻击
    yii rbac管理
    yii2.0 表单小部件常用的默认选中
    yii 表单小部件使用
    多个API接口
    iwebshop 增删改查
    搜索引擎接口
    2003终端服务器授权,120天试用期限制
  • 原文地址:https://www.cnblogs.com/zskbll/p/8490384.html
Copyright © 2011-2022 走看看