陶宇陽(yáng) 蔣玉茹 劉林峰 王巖
(北京信息科技大學(xué)計(jì)算機(jī)學(xué)院 北京市 100101)
隨著互聯(lián)網(wǎng)在的快速發(fā)展,學(xué)生們擁有了許多可以獲取知識(shí)的渠道,但是如何短期提升學(xué)生獲取知識(shí)的成就感使學(xué)生進(jìn)一步提升學(xué)習(xí)的動(dòng)力仍是一大重要問(wèn)題,同時(shí)在一局快節(jié)奏的對(duì)戰(zhàn)游戲中,利用自己已有的知識(shí)和問(wèn)題分析能力贏得比賽正是一種能快速獲得成就感的方式。
目前,已存在許多成熟的大型網(wǎng)絡(luò)學(xué)習(xí)平臺(tái)及互動(dòng)答題游戲形式,這些平臺(tái)普遍擁有很多的學(xué)習(xí)資源而游戲也擁有較為成熟的游戲方案,但是學(xué)習(xí)平臺(tái)很容易陷入“學(xué)不動(dòng),不想學(xué)”的困境,單純的游戲又與學(xué)習(xí)不相關(guān)。鑒于此,立足于當(dāng)前廣大學(xué)生的學(xué)習(xí)模式單一的情況,根據(jù)學(xué)生的學(xué)習(xí)需要,結(jié)合網(wǎng)絡(luò)對(duì)戰(zhàn)游戲能夠快速獲得成就感的特點(diǎn),本文設(shè)計(jì)并開(kāi)發(fā)了一款可以在線匹配多人組隊(duì)答題(專業(yè)知識(shí))的網(wǎng)絡(luò)對(duì)戰(zhàn)游戲,致力于提供在線匹配、多人組隊(duì)、同步答題、積分多者獲勝等輕量化、個(gè)性化的游戲平臺(tái)解決方案。
本項(xiàng)目所設(shè)計(jì)與開(kāi)發(fā)的系統(tǒng)與北京信息科技大學(xué)計(jì)算機(jī)學(xué)院的程序設(shè)計(jì)基礎(chǔ)(C 語(yǔ)言)過(guò)程化考核平臺(tái)緊密融合,已經(jīng)部署在校園內(nèi)網(wǎng)環(huán)境中。系統(tǒng)既以學(xué)生為主體,寓學(xué)于樂(lè),為學(xué)生提供更加輕松的學(xué)習(xí)環(huán)境,又在潛移默化中提高學(xué)生的程序設(shè)計(jì)及C 語(yǔ)言應(yīng)用水平,同時(shí),系統(tǒng)亦可幫助教師了解學(xué)生的學(xué)習(xí)情況,及時(shí)調(diào)整教學(xué)策略,最終使學(xué)生、教師和學(xué)校都可以獲益。
本系統(tǒng)包括基于Spring Boot 框架搭建的服務(wù)端和Android 客戶端。系統(tǒng)模塊結(jié)構(gòu)圖如圖1所示。
采用北京信息科技大學(xué)計(jì)算機(jī)學(xué)院的程序設(shè)計(jì)基礎(chǔ)(C 語(yǔ)言)過(guò)程化考核平臺(tái)的習(xí)題庫(kù)中的習(xí)題為出題內(nèi)容。習(xí)題庫(kù)中有困難、中等、容易三種評(píng)級(jí)的題目,由于困難評(píng)級(jí)的題目往往涉及長(zhǎng)代碼閱讀或復(fù)雜計(jì)算,通常不能在短時(shí)間內(nèi)解答,因此不適合在本對(duì)戰(zhàn)系統(tǒng)中使用,系統(tǒng)僅采用簡(jiǎn)單和中等兩種評(píng)級(jí)的題目。不同評(píng)級(jí)的題目有不同的答題時(shí)間,中等難度的題目答題時(shí)間為30 秒,容易難度的題目答題時(shí)間為10 秒。系統(tǒng)針對(duì)每一組成功匹配的用戶,從題庫(kù)中隨機(jī)抽取若干題目作為該組用戶的對(duì)戰(zhàn)題目。
對(duì)戰(zhàn)系統(tǒng)采用基于對(duì)戰(zhàn)積分的平衡匹配算法在匹配池中找到合適的一組用戶分成兩個(gè)隊(duì)伍組成對(duì)局。匹配算法盡可能保證對(duì)局雙方的平均水平接近,同時(shí),隊(duì)內(nèi)的各個(gè)成員水平接近。避免出現(xiàn)雙方的知識(shí)水平差距過(guò)大,使得對(duì)局失去了緊張刺激的感覺(jué),從而影響了用戶的游戲體驗(yàn)。
對(duì)局中,服務(wù)端通過(guò)統(tǒng)一消息指令的收發(fā),保證每道題目的內(nèi)容和選項(xiàng)盡可能同時(shí)出現(xiàn)在各個(gè)用戶的手機(jī)屏幕上,每個(gè)客戶端反應(yīng)在界面上的題目答題時(shí)限(倒計(jì)時(shí))也盡可能保持一致。
圖1:選擇題對(duì)戰(zhàn)系統(tǒng)系統(tǒng)模塊結(jié)構(gòu)圖
圖2:匹配算法的存儲(chǔ)結(jié)構(gòu)簡(jiǎn)略圖
每道題目都有相同的初始分?jǐn)?shù),題目分?jǐn)?shù)會(huì)隨著作答時(shí)間的流逝而減少。每名成員對(duì)每一道題僅有一次選擇答案的機(jī)會(huì),無(wú)論答案是否正確。若某一個(gè)成員選擇了正確的答案,那么其所屬的隊(duì)伍就會(huì)加分。分值是該成員選擇答案時(shí)的題目分?jǐn)?shù)。最后,隊(duì)伍得分高的一方獲勝。
對(duì)戰(zhàn)雙方想獲取勝利就要在盡可能短的時(shí)間內(nèi)選出正確答案,這樣的對(duì)戰(zhàn)規(guī)則保證了游戲有一定的競(jìng)技性,用戶在答題過(guò)程中,可以發(fā)現(xiàn)在課堂上沒(méi)有及時(shí)掌握的知識(shí)。不同于課堂上嚴(yán)肅的氣氛,相對(duì)緊張又不乏趣味的對(duì)戰(zhàn)過(guò)程可以加深用戶對(duì)平時(shí)容易忘記的細(xì)節(jié)知識(shí)點(diǎn)的記憶。同時(shí),選擇題的答題方式簡(jiǎn)單明確,不會(huì)像填空、解答題一樣產(chǎn)生語(yǔ)義上的誤差,適合在手機(jī)上操作,符合本系統(tǒng)在輕松使用時(shí)學(xué)習(xí)知識(shí)的設(shè)計(jì)初衷。
服務(wù)端分為對(duì)戰(zhàn)核心模塊和題目數(shù)據(jù)供給模塊。其中,對(duì)戰(zhàn)核心模塊提供網(wǎng)絡(luò)通信服務(wù)、匹配服務(wù)和對(duì)局服務(wù);題目數(shù)據(jù)供給模塊提供客戶端訪問(wèn)數(shù)據(jù)庫(kù)的HTTP 接口,按需求獲取題目信息。
對(duì)戰(zhàn)核心模塊下屬的各個(gè)服務(wù)獨(dú)立運(yùn)行于不同的線程中,通過(guò)消息隊(duì)列進(jìn)行線程間的通訊。
圖3:自動(dòng)機(jī)的圖結(jié)構(gòu)數(shù)據(jù)
(1)網(wǎng)絡(luò)通信服務(wù)負(fù)責(zé)與各客戶端建立連接,監(jiān)聽(tīng)并接收消息,發(fā)送消息,封裝消息為JavaBean。
(2)匹配服務(wù)運(yùn)行設(shè)計(jì)好的平衡匹配算法,接受客戶端的匹配請(qǐng)求,當(dāng)匹配系統(tǒng)得出一組匹配結(jié)果時(shí),將結(jié)果發(fā)送給對(duì)局服務(wù),創(chuàng)建對(duì)局。
(3)對(duì)局服務(wù)負(fù)責(zé)本系統(tǒng)的核心功能,調(diào)度對(duì)局的進(jìn)行階段。每一個(gè)對(duì)局獨(dú)立運(yùn)行于對(duì)局服務(wù)的子線程中,對(duì)局服務(wù)在創(chuàng)建新的對(duì)局時(shí),隨機(jī)生成一個(gè)對(duì)局ID,并通過(guò)鍵值對(duì)保存其對(duì)象。當(dāng)接收客戶端消息時(shí),通過(guò)鍵值對(duì),發(fā)送給指定的線程。
每一個(gè)服務(wù)的運(yùn)行模式均為:服務(wù)在各自的線程中運(yùn)行時(shí),會(huì)阻塞在從各自的消息隊(duì)列中獲取消息的步驟,阻塞時(shí)不會(huì)消耗CPU資源,當(dāng)服務(wù)從消息隊(duì)列中獲取到一條消息時(shí),會(huì)根據(jù)消息內(nèi)容進(jìn)行業(yè)務(wù)邏輯上的處理,處理完畢以后再一次阻塞在獲取消息的步驟。
客戶端收到服務(wù)端的指令后,調(diào)用服務(wù)端題目數(shù)據(jù)供給模塊的相關(guān)接口,獲取JSON 形式的題目信息,封裝并顯示。
本系統(tǒng)數(shù)據(jù)庫(kù)存儲(chǔ)三個(gè)實(shí)體信息:科目信息、題目信息和題目選項(xiàng)信息。其他信息,比如用戶信息及用戶身份驗(yàn)證,則通過(guò)北京信息科技大學(xué)計(jì)算機(jī)學(xué)院的程序設(shè)計(jì)基礎(chǔ)(C 語(yǔ)言)過(guò)程化考核平臺(tái)提供的相關(guān)接口實(shí)現(xiàn)管理及操作,無(wú)需單獨(dú)建立數(shù)據(jù)庫(kù)。
網(wǎng)絡(luò)通信服務(wù)基于NIO 技術(shù),與各客戶端建立TCP 長(zhǎng)連接,負(fù)責(zé)消息的發(fā)送、接收與封裝。消息分為兩類,分別為服務(wù)端向客戶端發(fā)送的ClientMessage,和客戶端向服務(wù)端發(fā)送的ServerMessage。這兩種消息均封裝為JavaBean,在類中規(guī)定消息結(jié)構(gòu)。當(dāng)其它服務(wù)需要向客戶端發(fā)送消息時(shí),通過(guò)向網(wǎng)絡(luò)通信服務(wù)的消息隊(duì)列發(fā)送消息,網(wǎng)絡(luò)通信服務(wù)將隊(duì)列中的JavaBean 消息對(duì)象出隊(duì),并讀取其中的數(shù)據(jù),寫(xiě)入字節(jié)緩沖區(qū)ByteBuffer,調(diào)用SocketChannel 類的write()方法,完成消息的發(fā)送;同時(shí),網(wǎng)絡(luò)通信服務(wù)的下屬子服務(wù)MessageReceiver,獨(dú)立運(yùn)行于一個(gè)線程中,負(fù)責(zé)通過(guò)NIO 的多路復(fù)用選擇器Selector,阻塞式監(jiān)聽(tīng)各客戶端的連接。若收到消息,則調(diào)用SocketChannel 的read()方法,讀取來(lái)自客戶端的消息數(shù)據(jù),并將其封裝為JavaBean 對(duì)象,然后后消息隊(duì)列發(fā)送給其它服務(wù)。
MessageReceiver的監(jiān)聽(tīng)及接收消息的邏輯,用偽代碼表示如下:
1.選擇器監(jiān)聽(tīng)到READ 事件;
2.將觸發(fā)READ 事件的SocketChannel 添加到集合中;
3.獲取集合的迭代器;
4.while(迭代器有剩余內(nèi)容) {
5.獲取觸發(fā)READ 事件的SocketChannel;
6.SocketChannel.read();
7.封裝消息為JavaBean;
8.發(fā)送JavaBean 給指定的服務(wù);
9.將當(dāng)前SocketChannel 從集合中刪除;
10.}
設(shè)計(jì)平衡匹配算法,以滿足下述目標(biāo):
(1)多個(gè)用戶進(jìn)行游戲時(shí),需要盡可能保持用戶間水平相近來(lái)給用戶更好的游戲體驗(yàn);
(2)需要權(quán)衡用戶等待時(shí)間與用戶間的水平差距孰先孰后的問(wèn)題。
為此,首先設(shè)計(jì)匹配隊(duì)列的數(shù)據(jù)結(jié)構(gòu):
(1)將發(fā)出匹配請(qǐng)求的用戶抽象為一個(gè)類,具有分?jǐn)?shù)和等待時(shí)間兩個(gè)屬性;
(2)利用集合存儲(chǔ)同一個(gè)分段的用戶
(3)從0 分起,每10 分為一個(gè)分段;
(4)利用有序數(shù)組存儲(chǔ)多個(gè)集合。
形成有序數(shù)組存儲(chǔ)多個(gè)集合、集合存儲(chǔ)多個(gè)用戶的數(shù)據(jù)結(jié)構(gòu)。
當(dāng)有新的用戶加入匹配隊(duì)列時(shí),根據(jù)用戶的分?jǐn)?shù)將其放置到數(shù)組特定下標(biāo)的集合中,服務(wù)端中的實(shí)現(xiàn)是將用戶置入數(shù)組下標(biāo)為用戶分?jǐn)?shù)除以10 的集合中去,即用戶分?jǐn)?shù)為2733 則置入第273 個(gè)集合中去。
每秒以集合為單位遍歷一次數(shù)組,當(dāng)數(shù)組中某一集合滿足游戲開(kāi)始所需要的人數(shù),則將這些用戶移出匹配隊(duì)列,組建成為一次游戲?qū)?。否則將獲取此集合中等待時(shí)間最長(zhǎng)的用戶,根據(jù)此用戶的等待時(shí)間向兩側(cè)一定距離內(nèi)的集合獲取在匹配中的用戶。服務(wù)端中的實(shí)現(xiàn)是向兩側(cè)距離小于用戶等待時(shí)間的平方的集合中獲取用戶,即假如用戶在匹配隊(duì)列中等待了5 秒,分?jǐn)?shù)為2307 分,那么在第230 個(gè)集合中用戶,如果用戶數(shù)量不足以開(kāi)始游戲,那么就會(huì)在239、238……205,231、232……255,這些集合中獲取用戶,直到達(dá)到游戲開(kāi)始的要求。
這樣可以發(fā)現(xiàn),只要整個(gè)匹配隊(duì)列中的用戶數(shù)量滿足游戲開(kāi)始的要求,那么在一分鐘以內(nèi)一定會(huì)成功組建游戲,如果匹配隊(duì)列中用戶較多,那么成功組建的對(duì)局中所有用戶的分?jǐn)?shù)的方差會(huì)盡可能小。
匹配算法的存儲(chǔ)結(jié)構(gòu)簡(jiǎn)略圖如圖2所示。
狀態(tài)自動(dòng)機(jī)是控制客戶端界面與后臺(tái)交互邏輯的核心。其設(shè)計(jì)思想包括:
(1)以有向圖結(jié)構(gòu)表示并存儲(chǔ)自動(dòng)機(jī)的執(zhí)行邏輯,圖節(jié)點(diǎn)表示狀態(tài),結(jié)點(diǎn)間的連線表示事件。
(2)用戶對(duì)客戶端的互動(dòng)行為(主要體現(xiàn)為點(diǎn)擊手機(jī)屏幕或點(diǎn)擊返回按鈕等),以及接收來(lái)自服務(wù)器的消息,均可觸發(fā)某種事件。
(3)每一個(gè)狀態(tài)均可由指定的某些事件,轉(zhuǎn)換成另一種狀態(tài)。
(4)在自動(dòng)機(jī)中維護(hù)一個(gè)變量currentStatus,表示自動(dòng)機(jī)的當(dāng)前狀態(tài)。
(5)自動(dòng)機(jī)通過(guò)剛剛被觸發(fā)的事件,從有向圖中查找下一個(gè)狀態(tài),并更新為當(dāng)前狀態(tài)。
(6)自動(dòng)機(jī)獨(dú)立運(yùn)行在一個(gè)線程中,通過(guò)Message 向界面線程發(fā)送指令以控制界面的變化。
(7)界面線程以及其他線程通過(guò)向自動(dòng)機(jī)的事件隊(duì)列發(fā)送剛剛被觸發(fā)的事件。
(8)自動(dòng)機(jī)的任務(wù)就是根據(jù)被觸發(fā)的事件,轉(zhuǎn)換當(dāng)前狀態(tài),并調(diào)用新?tīng)顟B(tài)的某個(gè)方法,執(zhí)行一系列邏輯。
(9)自動(dòng)機(jī)存儲(chǔ)并調(diào)用的所有狀態(tài)對(duì)象的類型,均為狀態(tài)的抽象父類。
(10)不同的狀態(tài)通過(guò)繼承同一個(gè)抽象父類,在同一個(gè)抽象方法中寫(xiě)入不同的具體實(shí)現(xiàn),供自動(dòng)機(jī)線程調(diào)用。
自動(dòng)機(jī)的圖結(jié)構(gòu)數(shù)據(jù)由圖3 表示。
本文設(shè)計(jì)與開(kāi)發(fā)了一個(gè)選擇題對(duì)戰(zhàn)系統(tǒng),基于SpringBoot 設(shè)計(jì)并實(shí)現(xiàn)了系統(tǒng)的服務(wù)端,基于Android 技術(shù)設(shè)計(jì)并實(shí)現(xiàn)了系統(tǒng)的客戶端。在客戶端利用自動(dòng)機(jī)機(jī)制設(shè)計(jì)人機(jī)交互邏輯;在服務(wù)器端利用NIO 技術(shù)設(shè)計(jì)高效網(wǎng)絡(luò)通訊架構(gòu)。所實(shí)現(xiàn)系統(tǒng)本系統(tǒng)以實(shí)現(xiàn)勞逸結(jié)合為目的,將專業(yè)知識(shí)的學(xué)習(xí)與游戲競(jìng)技的優(yōu)點(diǎn)融為一體,著重激發(fā)學(xué)生的學(xué)習(xí)興趣,減輕反饋不足所學(xué)習(xí)易產(chǎn)生的倦怠心理。本系統(tǒng)已經(jīng)實(shí)際部署于學(xué)校的過(guò)程考核平臺(tái)之中,心里,對(duì)游戲各個(gè)環(huán)節(jié)進(jìn)行設(shè)計(jì),提供既有娛樂(lè)性質(zhì)也可學(xué)習(xí)專業(yè)知識(shí)的對(duì)戰(zhàn)游戲。本系統(tǒng)具有較強(qiáng)的實(shí)用性,可以為用戶提供了完整的游戲較好的學(xué)習(xí)體驗(yàn)。