庖丁解牛-小程序版好友對戰答題項目實踐(一)


            

 

 

        新的一年已經拉開了序幕,有的忙着離職、有的忙着請求加薪,有的忙着春運,有人忙着相親。。

        對於絕大多數人來說,新的一年就是新的開始,新的開始也就是雄心壯志立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的開發與配置。

欲知后事如何,傾聽下回分解。

本文首發公眾號:微兔碼農說,歡迎關注,分享。

 

 

有的朋友要源碼。所有的源碼在整個系列發布完成后,會打包,供大家下載。如需文章中提到的數據庫文件,請掃描下方二維碼,關注微信公眾號,回復答題數據庫,即可獲取數據庫地址。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM