热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

庖丁解牛-小程序版好友对战答题项目实践(一)

序新的一年已经拉开了序幕,有的忙着离职、有的忙着请求加薪,有的忙着春运,有人忙着相亲。。对于绝大多数人来说,新的一年就是

            

 

 

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

        对于绝大多数人来说,新的一年就是新的开始,新的开始也就是雄心壮志立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的开发与配置。

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

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

 

 

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

 

 

 

 


推荐阅读
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
author-avatar
爱情黄昏泪的诱惑_494
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有