庖丁解牛-小程序版好友对战答题项目实践(一)
序
新的一年已经拉开了序幕,有的忙着离职、有的忙着请求加薪,有的忙着春运,有人忙着相亲。。
对于绝大多数人来说,新的一年就是新的开始,新的开始也就是雄心壮志立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的开发与配置。
欲知后事如何,倾听下回分解。
本文首发公众号:微兔码农说,欢迎关注,分享。
有的朋友要源码。所有的源码在整个系列发布完成后,会打包,供大家下载。如需文章中提到的数据库文件,请扫描下方二维码,关注微信公众号,回复答题数据库,即可获取数据库地址。