五子棋畢業(yè)設(shè)計(jì)說(shuō)明書(shū)_第1頁(yè)
已閱讀1頁(yè),還剩28頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、<p>  【摘要】本論文主要闡述以面向?qū)ο蟮某绦蜷_(kāi)發(fā)語(yǔ)言VC++為開(kāi)發(fā)工具,設(shè)計(jì)一個(gè)五子棋游戲。本系統(tǒng)是個(gè)小型游戲,可以單機(jī)使用,也可以網(wǎng)絡(luò)兩個(gè)人游戲,也可以和電腦進(jìn)行游戲。論文首先介紹了開(kāi)發(fā)背景及開(kāi)發(fā)語(yǔ)言的介紹。然后介紹設(shè)計(jì)該游戲的框架結(jié)構(gòu),然后介紹了程序的設(shè)計(jì)過(guò)程,以及程序的相關(guān)算法。</p><p>  關(guān)鍵詞:游戲, 系統(tǒng) ,圖片, VISUAL C++</p><p>

2、;<b>  目 錄</b></p><p>  1 引 言 11.1 五子棋介紹 11.2 開(kāi)發(fā)背景 11.3 開(kāi)發(fā)環(huán)境及運(yùn)行環(huán)境 11.3.1 開(kāi)發(fā)環(huán)境 11.3.2 運(yùn)行環(huán)境 12 軟件架構(gòu) 22.1 棋盤(pán)類(lèi) 22.2 游戲模式類(lèi) 33 棋盤(pán)類(lèi)——CTable 43.1 主要成員變量說(shuō)明 43.1.1 網(wǎng)絡(luò)連接標(biāo)志 43.1.2 棋盤(pán)等待標(biāo)志 43.1.3 網(wǎng)

3、絡(luò)套接字 43.1.4 棋盤(pán)數(shù)據(jù) 43.1.5 游戲模式指針 53.2 主要成員函數(shù)說(shuō)明 53.2.1 套接字的回調(diào)處理 53.2.2 清空棋盤(pán) 53.2.3 繪制棋子 53.2.4 左鍵消息 63.2.5 繪制棋盤(pán) 63.2.6 對(duì)方落子完畢 63.2.7 設(shè)置游戲模式 63.2.8 勝負(fù)的判斷 74 游戲模式類(lèi) 84.1 主要成員變量說(shuō)明 94.1.1 棋盤(pán)指針 94.1.2 落子步驟 94.2 主要

4、成員函數(shù)說(shuō)明 94.2.1 悔棋操作 94.2.2 初始化操作 94.2.3 接收來(lái)自對(duì)方的消息 104.2.4 發(fā)送落子消息 104.2.5 勝利后的處理 105 消息機(jī)制 115.1 消息機(jī)制的架構(gòu)</p><p><b>  1 引言</b></p><p><b>  1.1 五子棋介紹</b></p><

5、;p>  五子棋是起源于中國(guó)古代的傳統(tǒng)黑白棋種之一?,F(xiàn)代五子棋日文稱(chēng)之為“連珠”,英譯為“Renju”,英文稱(chēng)之為“Gobang”或“FIR”(Five in a Row的縮寫(xiě)),亦有“連五子”、“五子連”、“串珠”、“五目”、“五目碰”、“五格”等多種稱(chēng)謂。</p><p>  五子棋不僅能增強(qiáng)思維能力,提高智力,而且富含哲理,有助于修身養(yǎng)性。五子棋既有現(xiàn)代休閑的明顯特征“短、平、快”,又有古典哲學(xué)的高深

6、學(xué)問(wèn)“陰陽(yáng)易理”;它既有簡(jiǎn)單易學(xué)的特性,為人民群眾所喜聞樂(lè)見(jiàn),又有深?yuàn)W的技巧和高水平的國(guó)際性比賽;它的棋文化源淵流長(zhǎng),具有東方的神秘和西方的直觀;既有“場(chǎng)”的概念,亦有“點(diǎn)”的連接。它是中西文化的交流點(diǎn),是古今哲理的結(jié)晶。</p><p><b>  1.2 開(kāi)發(fā)背景</b></p><p>  當(dāng)前網(wǎng)絡(luò)上流傳的五子棋游戲功能并不盡善盡美,其中最主要的問(wèn)題就是人機(jī)對(duì)戰(zhàn)

7、和網(wǎng)絡(luò)對(duì)戰(zhàn)不能夠一起實(shí)現(xiàn),所以我決定開(kāi)發(fā)[1]一個(gè)既能夠人機(jī)對(duì)戰(zhàn),又能夠進(jìn)行網(wǎng)絡(luò)對(duì)戰(zhàn)的五子棋系統(tǒng)。</p><p>  1.3 開(kāi)發(fā)環(huán)境及運(yùn)行環(huán)境</p><p>  1.3.1 開(kāi)發(fā)環(huán)境</p><p>  Intel® Pentium® 4 2.0GHz,512M內(nèi)存,80G硬盤(pán)</p><p>  Microsoft

8、® Windows? 2000 Professional</p><p>  Microsoft® Visual C++ 6.0</p><p>  Microsoft® Developer Network for Visual Studio.NET 2003</p><p>  Visual Assist X 10.1.1301.0&

9、lt;/p><p>  1.3.2 運(yùn)行環(huán)境</p><p>  Intel® Pentium® 2及以上處理器,32M以上內(nèi)存,4G以上硬盤(pán)</p><p>  Microsoft® Windows? 9X/NT操作系統(tǒng)</p><p>  800*600或以上的屏幕分辨率</p><p>

10、<b>  2 軟件架構(gòu)</b></p><p>  軟件的總體架構(gòu)如圖2.1:</p><p><b>  圖2.1 軟件架構(gòu)</b></p><p>  考慮到整個(gè)的下棋過(guò)程(無(wú)論對(duì)方是電腦抑或其他網(wǎng)絡(luò)玩家)可以分為:己方落子、等待對(duì)方落子、對(duì)方落子、設(shè)置己方棋盤(pán)數(shù)據(jù)這一系列過(guò)程,因此一人游戲類(lèi)、二人游戲類(lèi)和棋盤(pán)類(lèi)之間

11、的關(guān)系參考了AbstractFactory(抽象工廠)模式,以實(shí)現(xiàn)對(duì)兩個(gè)不同模塊進(jìn)行一般化的控制。[2]</p><p><b>  2.1 棋盤(pán)類(lèi)</b></p><p>  整個(gè)架構(gòu)的核心部分,類(lèi)名為CTable。封裝了棋盤(pán)的各種可能用到的功能[3],如保存棋盤(pán)數(shù)據(jù)、初始化、判斷勝負(fù)等。用戶(hù)操作主界面,主界面與CTable進(jìn)行交互來(lái)完成對(duì)游戲的操作。</p&

12、gt;<p><b>  2.2 游戲模式類(lèi)</b></p><p>  用來(lái)管理人機(jī)對(duì)弈/網(wǎng)絡(luò)對(duì)弈兩種游戲模式,類(lèi)名為CGame。CGame是一個(gè)抽象類(lèi),經(jīng)由它派生出一人游戲類(lèi)COneGame和網(wǎng)絡(luò)游戲類(lèi)CTwoGame,如圖2.2:</p><p>  圖2.2 CGame類(lèi)派生關(guān)系</p><p>  這樣,CTable類(lèi)就

13、可以通過(guò)一個(gè)CGame類(lèi)的指針[4],在游戲初始化的時(shí)候根據(jù)具體游戲模式的要求實(shí)例化COneGame或CTwoGame類(lèi)的對(duì)象;然后利用多態(tài)性[5],使用CGame類(lèi)提供的公有接口就可以完成不同游戲模式下的不同功能了。</p><p>  3 棋盤(pán)類(lèi)——CTable</p><p>  3.1 主要成員變量說(shuō)明</p><p>  3.1.1 網(wǎng)絡(luò)連接標(biāo)志——m_b

14、Connected</p><p>  用來(lái)表示當(dāng)前網(wǎng)絡(luò)連接的情況,在網(wǎng)絡(luò)對(duì)弈游戲模式下客戶(hù)端連接服務(wù)器的時(shí)候用來(lái)判斷是否連接成功;事實(shí)上,它也是區(qū)分當(dāng)前游戲模式的唯一標(biāo)志。</p><p>  3.1.2 棋盤(pán)等待標(biāo)志——m_bWait與m_bOldWait</p><p>  由于在玩家落子后需要等待對(duì)方落子,m_bWait標(biāo)志就用來(lái)標(biāo)識(shí)棋盤(pán)的等待狀態(tài)。當(dāng)m_b

15、Wait為T(mén)RUE時(shí),是不允許玩家落子的。</p><p>  在網(wǎng)絡(luò)對(duì)弈模式下,玩家之間需要互相發(fā)送諸如悔棋、和棋這一類(lèi)的請(qǐng)求消息,在發(fā)送請(qǐng)求后等待對(duì)方回應(yīng)時(shí),也是不允許落子的,所以需要將m_bWait標(biāo)志置為T(mén)RUE。在收到對(duì)方回應(yīng)后,需要恢復(fù)原有的棋盤(pán)等待狀態(tài),所以需要另外一個(gè)變量在發(fā)送請(qǐng)求之前保存棋盤(pán)的等待狀態(tài)做恢復(fù)之用,也就是m_bOldWait。</p><p>  等待標(biāo)志的

16、設(shè)置,由成員函數(shù)SetWait和RestoreWait完成。</p><p>  3.1.3 網(wǎng)絡(luò)套接字——m_sock和m_conn</p><p>  在網(wǎng)絡(luò)對(duì)弈游戲模式下,需要用到這兩個(gè)套接字對(duì)象。其中m_sock對(duì)象用于做服務(wù)器時(shí)的監(jiān)聽(tīng)之用,m_conn用于網(wǎng)絡(luò)連接的傳輸。</p><p>  3.1.4 棋盤(pán)數(shù)據(jù)——m_data</p>&l

17、t;p>  這是一個(gè)15*15的二位數(shù)組,用來(lái)保存當(dāng)前棋盤(pán)的落子數(shù)據(jù)。其中對(duì)于每個(gè)成員來(lái)說(shuō),0表示落黑子,1表示落白子,-1表示無(wú)子。</p><p>  3.1.5 游戲模式指針——m_pGame</p><p>  這個(gè)CGame類(lèi)的對(duì)象指針是CTable類(lèi)的核心內(nèi)容。它所指向的對(duì)象實(shí)體決定了CTable在執(zhí)行一件事情時(shí)候的不同行為,具體的內(nèi)容請(qǐng)參見(jiàn)“游戲模式”一節(jié)。</p

18、><p>  3.2 主要成員函數(shù)說(shuō)明</p><p>  3.2.1 套接字的回調(diào)處理——Accept、Connect、Receive</p><p>  本程序的套接字派生自MFC的CAsyncSocket類(lèi)[6],CTable的這三個(gè)成員函數(shù)就分別提供了對(duì)套接字[7]回調(diào)事件OnAccept、OnConnect、OnReceive的實(shí)際處理,其中尤以Receive

19、成員函數(shù)重要,它之中包含了對(duì)所有網(wǎng)絡(luò)消息(參見(jiàn)“消息機(jī)制”一節(jié))的分發(fā)處理。</p><p>  3.2.2 清空棋盤(pán)——Clear</p><p>  在每一局游戲開(kāi)始的時(shí)候都需要調(diào)用這個(gè)函數(shù)將棋盤(pán)清空,也就是棋盤(pán)的初始化工作。在這個(gè)函數(shù)中,主要發(fā)生了這么幾件事情:</p><p>  將m_data中每一個(gè)落子位都置為無(wú)子狀態(tài)(-1)。</p>&

20、lt;p>  按照傳入的參數(shù)設(shè)置棋盤(pán)等待標(biāo)志m_bWait,以供先、后手的不同情況之用。</p><p>  使用delete將m_pGame指針?biāo)赶虻脑杏螒蚰J綄?duì)象從堆上刪除。</p><p>  3.2.3 繪制棋子——Draw</p><p>  這無(wú)疑是很重要的一個(gè)函數(shù),它根據(jù)參數(shù)給定的坐標(biāo)和顏色繪制棋子。繪制的詳細(xì)過(guò)程如下:</p>

21、<p>  將給定的棋盤(pán)坐標(biāo)換算為繪圖的像素坐標(biāo)。</p><p>  根據(jù)坐標(biāo)繪制棋子位圖。</p><p>  如果先前曾下過(guò)棋子,則利用R2_NOTXORPEN將上一個(gè)繪制棋子上的最后落子指示矩形擦除。</p><p>  在剛繪制完成的棋子四周繪制最后落子指示矩形。</p><p>  3.2.4 左鍵消息——OnLBut

22、tonUp</p><p>  作為棋盤(pán)唯一響應(yīng)的左鍵消息,也需要做不少的工作:</p><p>  如果棋盤(pán)等待標(biāo)志m_bWait為T(mén)RUE,則直接發(fā)出警告聲音并返回,即禁止落子。</p><p>  如果點(diǎn)擊時(shí)的鼠標(biāo)坐標(biāo)在合法坐標(biāo)(0, 0)~(14, 14)之外,亦禁止落子。</p><p>  如果走的步數(shù)大于1步,方才允許悔棋。&l

23、t;/p><p>  進(jìn)行勝利判斷,如勝利則修改UI狀態(tài)并增加勝利數(shù)的統(tǒng)計(jì)。</p><p>  如未勝利,則向?qū)Ψ桨l(fā)送已經(jīng)落子的消息。</p><p>  落子完畢,將m_bWait標(biāo)志置為T(mén)RUE,開(kāi)始等待對(duì)方回應(yīng)。</p><p>  3.2.5 繪制棋盤(pán)——OnPaint</p><p>  每當(dāng)WM_PAINT消

24、息觸發(fā)時(shí),都需要對(duì)棋盤(pán)進(jìn)行重繪。OnPaint作為響應(yīng)繪制消息的消息處理函數(shù)使用了雙緩沖技術(shù),減少了多次繪圖可能導(dǎo)致的圖像閃爍問(wèn)題。這個(gè)函數(shù)主要完成了以下工作:</p><p>  裝載棋盤(pán)位圖并進(jìn)行繪制。</p><p>  根據(jù)棋盤(pán)數(shù)據(jù)繪制棋子。</p><p>  繪制最后落子指示矩形。</p><p>  3.2.6 對(duì)方落子完畢——

25、Over</p><p>  在對(duì)方落子之后,仍然需要做一些判斷工作,這些工作與OnLButtonUp中的類(lèi)似,在此不再贅述。</p><p>  3.2.7 設(shè)置游戲模式——SetGameMode</p><p>  這個(gè)函數(shù)通過(guò)傳入的游戲模式參數(shù)對(duì)m_pGame指針進(jìn)行了初始化,代碼如下:</p><p>  void CTable::S

26、etGameMode( int nGameMode )</p><p><b>  {</b></p><p>  if ( 1 == nGameMode )</p><p>  m_pGame = new COneGame( this );</p><p><b>  else</b></p

27、><p>  m_pGame = new CTwoGame( this );</p><p>  m_pGame->Init();</p><p><b>  }</b></p><p>  這之后,就可以利用OO的繼承和多態(tài)特點(diǎn)[8]來(lái)使m_pGame指針使用相同的調(diào)用來(lái)完成不同的工作了,事實(shí)上,COneGame::

28、Init和CTwoGame::Init都是不同的。</p><p>  3.2.8 勝負(fù)的判斷——Win</p><p>  這是游戲中一個(gè)極其重要的算法,用來(lái)判斷當(dāng)前棋盤(pán)的形勢(shì)是哪一方獲勝。其詳細(xì)內(nèi)容請(qǐng)參見(jiàn)“主要算法”一節(jié)。</p><p>  4 游戲模式類(lèi)——CGame</p><p>  這個(gè)類(lèi)負(fù)責(zé)對(duì)游戲模式進(jìn)行管理,以及在不同的游戲

29、模式下對(duì)不同的用戶(hù)行為進(jìn)行不同的響應(yīng)。由于并不需要CGame本身進(jìn)行響應(yīng),所以將其設(shè)計(jì)為了一個(gè)純虛類(lèi)[9],它的定義如下:</p><p>  class CGame</p><p><b>  {</b></p><p>  protected:</p><p>  CTable *m_pTable;</p>

30、;<p><b>  public:</b></p><p><b>  // 落子步驟</b></p><p>  list< STEP > m_StepList;</p><p><b>  public:</b></p><p><b>

31、;  // 構(gòu)造函數(shù)</b></p><p>  CGame( CTable *pTable ) : m_pTable( pTable ) {}</p><p><b>  // 析構(gòu)函數(shù)</b></p><p>  virtual ~CGame();</p><p>  // 初始化工作,不同的游戲方式初始

32、化也不一樣</p><p>  virtual void Init() = 0;</p><p>  // 處理勝利后的情況,CTwoGame需要改寫(xiě)此函數(shù)完成善后工作</p><p>  virtual void Win( const STEP& stepSend );</p><p><b>  // 發(fā)送己方落子<

33、;/b></p><p>  virtual void SendStep( const STEP& stepSend ) = 0;</p><p><b>  // 接收對(duì)方消息</b></p><p>  virtual void ReceiveMsg( MSGSTRUCT *pMsg ) = 0;</p><

34、;p><b>  // 發(fā)送悔棋請(qǐng)求</b></p><p>  virtual void Back() = 0;</p><p><b>  };</b></p><p>  4.1 主要成員變量說(shuō)明</p><p>  4.1.1 棋盤(pán)指針——m_pTable</p><

35、;p>  由于在游戲中需要對(duì)棋盤(pán)以及棋盤(pán)的父窗口——主對(duì)話框進(jìn)行操作及UI狀態(tài)設(shè)置,故為CGame類(lèi)設(shè)置了這個(gè)成員。當(dāng)對(duì)主對(duì)話框進(jìn)行操作時(shí),可以使用m_pTable->GetParent()得到它的窗口指針。</p><p>  4.1.2 落子步驟——m_StepList</p><p>  一個(gè)好的棋類(lèi)程序必須要考慮到的功能就是它的悔棋功能,所以需要為游戲類(lèi)設(shè)置一個(gè)落子步驟

36、的列表。由于人機(jī)對(duì)弈和網(wǎng)絡(luò)對(duì)弈中都需要這個(gè)功能,故將這個(gè)成員直接設(shè)置到基類(lèi)CGame中。另外,考慮到使用的簡(jiǎn)便性,這個(gè)成員使用了C++標(biāo)準(zhǔn)模板庫(kù)[10](Standard Template Library,STL)中的std::list,而不是MFC的CList。</p><p>  4.2 主要成員函數(shù)說(shuō)明</p><p>  4.2.1 悔棋操作——Back</p>&l

37、t;p>  在不同的游戲模式下,悔棋的行為是不一樣的。</p><p>  人機(jī)對(duì)弈模式下,計(jì)算機(jī)是完全允許玩家悔棋的,但是出于對(duì)程序負(fù)荷的考慮(此原因請(qǐng)參見(jiàn)“幾點(diǎn)補(bǔ)充說(shuō)明”一節(jié)),只允許玩家悔當(dāng)前的兩步棋(計(jì)算機(jī)一步,玩家一步)。</p><p>  雙人網(wǎng)絡(luò)對(duì)弈模式下,悔棋的過(guò)程為:首先由玩家向?qū)Ψ桨l(fā)送悔棋請(qǐng)求(悔棋消息),然后由對(duì)方?jīng)Q定是否允許玩家悔棋,在玩家得到對(duì)方的響應(yīng)消息

38、(允許或者拒絕)之后,才進(jìn)行悔棋與否的操作。</p><p>  4.2.2 初始化操作——Init</p><p>  對(duì)于不同的游戲模式而言,也就有不同的初始化方式。對(duì)于人機(jī)對(duì)弈模式而言,初始化操作包括以下幾個(gè)步驟:</p><p>  設(shè)置網(wǎng)絡(luò)連接狀態(tài)m_bConnected為FALSE。</p><p>  設(shè)置主界面計(jì)算機(jī)玩家的姓名

39、。</p><p>  初始化所有的獲勝組合。</p><p>  如果是計(jì)算機(jī)先走,則占據(jù)天元(棋盤(pán)正中央)的位置。</p><p>  網(wǎng)絡(luò)對(duì)弈的初始化工作暫為空,以供以后擴(kuò)展之用。</p><p>  4.2.3 接收來(lái)自對(duì)方的消息——ReceiveMsg</p><p>  這個(gè)成員函數(shù)由CTable棋盤(pán)類(lèi)的R

40、eceive成員函數(shù)調(diào)用,用于接收來(lái)自對(duì)方的消息。對(duì)于人機(jī)對(duì)弈游戲模式來(lái)說(shuō),所能接收到的就僅僅是本地模擬的落子消息MSG_PUTSTEP;對(duì)于網(wǎng)絡(luò)對(duì)弈游戲模式來(lái)說(shuō),這個(gè)成員函數(shù)則負(fù)責(zé)從套接字讀取對(duì)方發(fā)過(guò)來(lái)的數(shù)據(jù),然后將這些數(shù)據(jù)解釋為自定義的消息結(jié)構(gòu),并回到CTable::Receive來(lái)進(jìn)行處理。</p><p>  4.2.4 發(fā)送落子消息——SendStep</p><p>  在玩家

41、落子結(jié)束后,要向?qū)Ψ桨l(fā)送自己落子的消息。對(duì)于不同的游戲模式,發(fā)送的目標(biāo)也不同:</p><p>  對(duì)于人機(jī)對(duì)弈游戲模式,將直接把落子的信息(坐標(biāo)、顏色)發(fā)送給COneGame類(lèi)相應(yīng)的計(jì)算函數(shù)。</p><p>  對(duì)于網(wǎng)絡(luò)對(duì)弈游戲模式,將把落子消息發(fā)送給套接字,并由套接字轉(zhuǎn)發(fā)給對(duì)方。</p><p>  4.2.5 勝利后的處理——Win</p>&

42、lt;p>  這個(gè)成員函數(shù)主要針對(duì)CTwoGame網(wǎng)絡(luò)對(duì)弈模式。在玩家贏得棋局后,這個(gè)函數(shù)仍然會(huì)調(diào)用SendStep將玩家所下的制勝落子步驟發(fā)送給對(duì)方玩家,然后對(duì)方的游戲端經(jīng)由CTable::Win來(lái)判定自己失敗。</p><p><b>  5 消息機(jī)制</b></p><p>  Windows系統(tǒng)擁有自己的消息機(jī)制,在不同事件發(fā)生的時(shí)候,系統(tǒng)也可以提供不同

43、的響應(yīng)方式[11]。五子棋程序也模仿Windows系統(tǒng)實(shí)現(xiàn)了自己的消息機(jī)制,主要為網(wǎng)絡(luò)對(duì)弈服務(wù),以響應(yīng)多種多樣的網(wǎng)絡(luò)消息。</p><p>  5.1 消息機(jī)制的架構(gòu)</p><p>  當(dāng)繼承自CAsyncSocket的套接字類(lèi)CFiveSocket收到消息時(shí),會(huì)觸發(fā)CFiveSocket::OnReceive事件[12],在這個(gè)事件中調(diào)用CTable::Receive,CTable::

44、Receive開(kāi)始按照自定義的消息格式接收套接字發(fā)送的數(shù)據(jù),并對(duì)不同的消息類(lèi)型進(jìn)行分發(fā)處理。</p><p>  圖5.1 自定義的消息機(jī)制</p><p>  如圖5.1所示,當(dāng)CTable獲得了來(lái)自網(wǎng)絡(luò)的消息之后,就可以使用一個(gè)switch結(jié)構(gòu)來(lái)進(jìn)行消息的分發(fā)了。</p><p>  5.2 各種消息說(shuō)明</p><p>  網(wǎng)絡(luò)間傳遞的

45、消息,都遵循以下一個(gè)結(jié)構(gòu)體的形式:</p><p>  // 摘自Messages.h</p><p>  typedef struct _tagMsgStruct {</p><p><b>  // 消息ID</b></p><p>  UINT uMsg;</p><p><b>

46、  // 落子信息</b></p><p><b>  int x;</b></p><p><b>  int y;</b></p><p>  int color;</p><p><b>  // 消息內(nèi)容</b></p><p>  

47、TCHAR szMsg[128];</p><p>  } MSGSTRUCT;</p><p>  隨著uMsg表示消息ID,x、y表示落子的坐標(biāo),color表示落子的顏色,szMsg隨著uMsg的不同而有不同的含義。</p><p>  5.2.1 落子消息——MSG_PUTSTEP</p><p>  表明對(duì)方落下了一個(gè)棋子,其中x、y

48、和color成員有效,szMsg成員無(wú)效。在人機(jī)對(duì)弈游戲模式下,亦會(huì)模擬發(fā)送此消息以達(dá)到程序模塊一般化的效果。</p><p>  5.2.2 悔棋消息——MSG_BACK</p><p>  表明對(duì)方請(qǐng)求悔棋,除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,會(huì)彈出MessageBox詢(xún)問(wèn)是否接受對(duì)方的請(qǐng)求(如圖5.2所示),并根據(jù)玩家的選擇回返MSG_AGREEBACK或MSG_REFU

49、SEBACK消息。另外,在發(fā)送這個(gè)消息之后,主界面上的某些元素將不再響應(yīng)用戶(hù)的操作。</p><p><b>  圖5.2 請(qǐng)求悔棋</b></p><p>  5.2.3 同意悔棋消息——MSG_AGREEBACK</p><p>  表明對(duì)方接受了玩家的悔棋請(qǐng)求,除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,將進(jìn)行正常的悔棋操作。<

50、/p><p>  5.2.4 拒絕悔棋消息——MSG_REFUSEBACK</p><p>  表明對(duì)方拒絕了玩家的悔棋請(qǐng)求(如圖5.3所示),除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,整個(gè)界面將恢復(fù)發(fā)送悔棋請(qǐng)求前的狀態(tài)。</p><p><b>  圖5.3 拒絕悔棋</b></p><p>  5.2.5 和棋消息

51、——MSG_DRAW</p><p>  表明對(duì)方請(qǐng)求和棋,除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,會(huì)彈出MessageBox詢(xún)問(wèn)是否接受對(duì)方的請(qǐng)求(如圖5.4所示),并根據(jù)玩家的選擇回返MSG_AGREEDRAW或MSG_REFUSEDRAW消息。另外,在發(fā)送這個(gè)消息之后,主界面上的某些元素將不再響應(yīng)用戶(hù)的操作。</p><p><b>  圖5.4 請(qǐng)求和棋</

52、b></p><p>  5.2.6 同意和棋消息——MSG_AGREEDRAW</p><p>  表明對(duì)方接受了玩家的和棋請(qǐng)求(如圖5.5所示),除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,雙方和棋。</p><p><b>  圖5.5 同意和棋</b></p><p>  5.2.7 拒絕和棋消息——M

53、SG_REFUSEDRAW</p><p>  表明對(duì)方拒絕了玩家的和棋請(qǐng)求(如圖5.6所示),除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,整個(gè)界面將恢復(fù)發(fā)送和棋請(qǐng)求前的狀態(tài)。</p><p><b>  圖5.6 拒絕和棋</b></p><p>  5.2.8 認(rèn)輸消息——MSG_GIVEUP</p><p> 

54、 表明對(duì)方已經(jīng)投子認(rèn)輸(如圖5.7所示),除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,整個(gè)界面將轉(zhuǎn)換為勝利后的狀態(tài)。</p><p><b>  圖5.7 認(rèn)輸</b></p><p>  5.2.9 聊天消息——MSG_CHAT</p><p>  表明對(duì)方發(fā)送了一條聊天信息,szMsg表示對(duì)方的信息,其余成員無(wú)效。接到這個(gè)信息后,會(huì)將對(duì)

55、方聊天的內(nèi)容顯示在主對(duì)話框的聊天記錄窗口內(nèi)。</p><p>  5.2.10 對(duì)方信息消息——MSG_INFORMATION</p><p>  用來(lái)獲取對(duì)方玩家的姓名,szMsg表示對(duì)方的姓名,其余成員無(wú)效。在開(kāi)始游戲的時(shí)候,由客戶(hù)端向服務(wù)端發(fā)送這條消息,服務(wù)端接到后設(shè)置對(duì)方的姓名,并將自己的姓名同樣用這條消息回發(fā)給客戶(hù)端。</p><p>  5.2.11 再

56、次開(kāi)局消息——MSG_PLAYAGAIN</p><p>  表明對(duì)方希望開(kāi)始一局新的棋局,除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,會(huì)彈出MessageBox詢(xún)問(wèn)是否接受對(duì)方的請(qǐng)求(如圖5.8所示),并根據(jù)玩家的選擇回返MSG_AGREEAGAIN消息或直接斷開(kāi)網(wǎng)絡(luò)。</p><p><b>  圖5.8 再次開(kāi)局</b></p><p&g

57、t;  5.2.12 同意再次開(kāi)局消息——MSG_AGREEAGAIN</p><p>  表明對(duì)方同意了再次開(kāi)局的請(qǐng)求,除uMsg成員外其余成員皆無(wú)效。接到這個(gè)消息后,將開(kāi)啟一局新游戲。</p><p><b>  6 主要算法</b></p><p>  五子棋游戲中,有相當(dāng)?shù)钠撬惴ǖ牟糠?。無(wú)論是人機(jī)對(duì)弈,還是網(wǎng)絡(luò)對(duì)弈,都需要合理算法的

58、支持,本節(jié)中將詳細(xì)介紹五子棋中使用的算法。[13]</p><p><b>  6.1 判斷勝負(fù)</b></p><p>  五子棋的勝負(fù),在于判斷棋盤(pán)上是否有一個(gè)點(diǎn),從這個(gè)點(diǎn)開(kāi)始的右、下、右下、左下四個(gè)方向是否有連續(xù)的五個(gè)同色棋子出現(xiàn),如圖6.1:</p><p>  圖6.1 判斷勝負(fù)方向</p><p>  這個(gè)算

59、法也就是CTable的Win成員函數(shù)。從設(shè)計(jì)的思想上,需要它接受一個(gè)棋子顏色的參數(shù),然后返回一個(gè)布爾值,這個(gè)值來(lái)指示是否勝利,代碼如下:</p><p>  BOOL CTable::Win( int color ) const</p><p><b>  {</b></p><p><b>  int x, y;</b>

60、</p><p><b>  // 判斷橫向</b></p><p>  for ( y = 0; y < 15; y++ )</p><p><b>  {</b></p><p>  for ( x = 0; x < 11; x++ )</p><p><

61、;b>  {</b></p><p>  if ( color == m_data[x][y] &&</p><p>  color == m_data[x + 1][y] &&</p><p>  color == m_data[x + 2][y] &&</p><p>  

62、color == m_data[x + 3][y] &&</p><p>  color == m_data[x + 4][y] )</p><p><b>  {</b></p><p>  return TRUE;</p><p><b>  }</b></p>&

63、lt;p><b>  }</b></p><p><b>  }</b></p><p><b>  // 判斷縱向</b></p><p>  for ( y = 0; y < 11; y++ )</p><p><b>  {</b><

64、;/p><p>  for ( x = 0; x < 15; x++ )</p><p><b>  {</b></p><p>  if ( color == m_data[x][y] &&</p><p>  color == m_data[x][y + 1] &&</p>

65、;<p>  color == m_data[x][y + 2] &&</p><p>  color == m_data[x][y + 3] &&</p><p>  color == m_data[x][y + 4] )</p><p><b>  {</b></p><p&

66、gt;  return TRUE;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  // 判斷“\”方向</p><p>  for ( y = 0; y <

67、; 11; y++ )</p><p><b>  {</b></p><p>  for ( x = 0; x < 11; x++ )</p><p><b>  {</b></p><p>  if ( color == m_data[x][y] &&</p>

68、<p>  color == m_data[x + 1][y + 1] &&</p><p>  color == m_data[x + 2][y + 2] &&</p><p>  color == m_data[x + 3][y + 3] &&</p><p>  color == m_data[x +

69、 4][y + 4] )</p><p><b>  {</b></p><p>  return TRUE;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b>&

70、lt;/p><p>  // 判斷“/”方向</p><p>  for ( y = 0; y < 11; y++ )</p><p><b>  {</b></p><p>  for ( x = 4; x < 15; x++ )</p><p><b>  {</b&g

71、t;</p><p>  if ( color == m_data[x][y] &&</p><p>  color == m_data[x - 1][y + 1] &&</p><p>  color == m_data[x - 2][y + 2] &&</p><p>  color ==

72、m_data[x - 3][y + 3] &&</p><p>  color == m_data[x - 4][y + 4] )</p><p><b>  {</b></p><p>  return TRUE;</p><p><b>  }</b></p>&l

73、t;p><b>  }</b></p><p><b>  }</b></p><p>  // 不滿(mǎn)足勝利條件</p><p>  return FALSE;</p><p><b>  }</b></p><p>  需要說(shuō)明的一點(diǎn)是,由于這個(gè)

74、算法所遵循的搜索順序是從左到右、自上而下,因此在每次循環(huán)的時(shí)候,都有一些坐標(biāo)無(wú)需納入考慮范圍。例如對(duì)于橫向判斷而言,由于右邊界所限,因而所有橫坐標(biāo)大于等于11的點(diǎn),都構(gòu)不成達(dá)到五子連的條件,所以橫坐標(biāo)的循環(huán)上界也就定為11,這樣也就提高了搜索的速度。</p><p>  6.2 人機(jī)對(duì)弈算法</p><p>  人機(jī)對(duì)弈算法完全按照CGame基類(lèi)定義的接口標(biāo)準(zhǔn),封裝在了COneGame派生

75、類(lèi)之中。下面將對(duì)這個(gè)算法進(jìn)行詳細(xì)地介紹。[14]</p><p>  6.2.1 獲勝組合</p><p>  獲勝組合是一個(gè)三維數(shù)組,它記錄了所有取勝的情況。也就是說(shuō),參考于CTable::Win中的情況,對(duì)于每一個(gè)落子坐標(biāo),獲勝的組合一共有</p><p>  15 * 11 * 2 + 11 * 11 * 2 = 572種。</p><p&

76、gt;  而對(duì)于每個(gè)坐標(biāo)的獲勝組合,應(yīng)該設(shè)置一個(gè)[15][15][572]大小的三維數(shù)組。</p><p>  在擁有了這些獲勝組合之后,就可以參照每個(gè)坐標(biāo)的572種組合給自己的局面和玩家的局面進(jìn)行打分,也就是根據(jù)當(dāng)前盤(pán)面中某一方所擁有的獲勝組合多少進(jìn)行權(quán)值的估算,給出最有利于自己的一步落子坐標(biāo)。</p><p>  由于是雙方對(duì)弈,所以游戲的雙方都需要一份獲勝組合,也就是:</p&

77、gt;<p>  bool m_Computer[15][15][572]; // 電腦獲勝組合</p><p>  bool m_Player[15][15][572]; // 玩家獲勝組合</p><p>  在每次游戲初始化(COneGame::Init)的時(shí)候,需要將每個(gè)坐標(biāo)下可能的獲勝組合都置為true。</p><p>  此外,還需要設(shè)置

78、計(jì)算機(jī)和玩家在各個(gè)獲勝組合中所填入的棋子數(shù):</p><p>  int m_Win[2][572];</p><p>  在初始化的時(shí)候,將每個(gè)棋子數(shù)置為0。</p><p>  6.2.2 落子后處理</p><p>  每當(dāng)一方落子后,都需要作如下處理:</p><p>  如果己方此坐標(biāo)的獲勝組合仍為true,

79、且仍有可能在此獲勝組合處添加棋子,則將此獲勝組合添加棋子數(shù)加1;</p><p>  如果對(duì)方此坐標(biāo)的獲勝組合仍為true,則將對(duì)方此坐標(biāo)的獲勝組合置為false,并將對(duì)方此獲勝組合添加棋子數(shù)置為-1(不可能靠此組合獲勝)。</p><p>  以玩家落子為例,代碼為:</p><p>  for ( i = 0; i < 572; i++ )</p&g

80、t;<p><b>  {</b></p><p><b>  // 修改狀態(tài)變化</b></p><p>  if ( m_Player[stepPut.x][stepPut.y][i] &&</p><p>  m_Win[0][i] != -1 )</p><p>

81、;  m_Win[0][i]++;</p><p>  if ( m_Computer[stepPut.x][stepPut.y][i] )</p><p><b>  {</b></p><p>  m_Computer[stepPut.x][stepPut.y][i] = false;</p><p>  m_Win

82、[1][i] = -1;</p><p><b>  }</b></p><p><b>  }</b></p><p>  6.2.3 查找棋盤(pán)空位</p><p>  在計(jì)算機(jī)落子之前,需要查找棋盤(pán)的空位,所以需要一個(gè)SearchBlank成員函數(shù)完成此項(xiàng)工作,此函數(shù)需要進(jìn)行不重復(fù)的查找,也就是

83、說(shuō),對(duì)已查找過(guò)的空位進(jìn)行標(biāo)記,并返回找到空位的坐標(biāo),其代碼如下:</p><p>  bool COneGame::SearchBlank( int &i, int &j,</p><p>  int nowTable[][15] )</p><p><b>  {</b></p><p><b&g

84、t;  int x, y;</b></p><p>  for ( x = 0; x < 15; x++ )</p><p><b>  {</b></p><p>  for ( y = 0; y < 15; y++ )</p><p><b>  {</b></p&

85、gt;<p>  if ( nowTable[x][y] == -1 && nowTable[x][y] != 2 )</p><p><b>  {</b></p><p><b>  i = x;</b></p><p><b>  j = y;</b></p&

86、gt;<p>  return true;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  return false;</p><p><b&

87、gt;  }</b></p><p>  6.2.4 落子打分</p><p>  找到空位后,需要對(duì)這個(gè)點(diǎn)的落子進(jìn)行打分,這個(gè)分?jǐn)?shù)也就是這個(gè)坐標(biāo)重要性的體現(xiàn),代碼如下:</p><p>  int COneGame::GiveScore( const STEP& stepPut )</p><p><b>  

88、{</b></p><p>  int i, nScore = 0;</p><p>  for ( i = 0; i < 572; i++ )</p><p><b>  {</b></p><p>  if ( m_pTable->GetColor() == stepPut.color )&l

89、t;/p><p><b>  {</b></p><p><b>  // 玩家下</b></p><p>  if ( m_Player[stepPut.x][stepPut.y][i] )</p><p><b>  {</b></p><p>  sw

90、itch ( m_Win[0][i] )</p><p><b>  {</b></p><p><b>  case 1:</b></p><p>  nScore -= 5;</p><p><b>  break;</b></p><p><

91、b>  case 2:</b></p><p>  nScore -= 50;</p><p><b>  break;</b></p><p><b>  case 3:</b></p><p>  nScore -= 500;</p><p><b

92、>  break;</b></p><p><b>  case 4:</b></p><p>  nScore -= 5000;</p><p><b>  break;</b></p><p><b>  default:</b></p>&

93、lt;p><b>  break;</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  else</b></p>

94、<p><b>  {</b></p><p><b>  // 計(jì)算機(jī)下</b></p><p>  if ( m_Computer[stepPut.x][stepPut.y][i] )</p><p><b>  {</b></p><p>  switch

95、( m_Win[1][i] )</p><p><b>  {</b></p><p><b>  case 1:</b></p><p>  nScore += 5;</p><p><b>  break;</b></p><p><b>

96、  case 2:</b></p><p>  nScore += 50;</p><p><b>  break;</b></p><p><b>  case 3:</b></p><p>  nScore += 100;</p><p><b> 

97、 break;</b></p><p><b>  case 4:</b></p><p>  nScore += 10000;</p><p><b>  break;</b></p><p><b>  default:</b></p><p

98、><b>  break;</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p

99、>  return nScore;</p><p><b>  }</b></p><p>  如代碼所示,考慮到攻守兩方面的需要,所以將玩家落子給的分?jǐn)?shù)置為負(fù)值。</p><p>  6.2.5 防守策略</p><p>  落子的考慮不單單要從進(jìn)攻考慮,還要從防守考慮。這一細(xì)節(jié)的實(shí)現(xiàn)其實(shí)就是讓計(jì)算機(jī)從玩家棋盤(pán)布

100、局分析戰(zhàn)況,然后找出對(duì)玩家最有利的落子位置。整個(gè)過(guò)程如下:</p><p>  for ( m = 0; m < 572; m++ )</p><p><b>  {</b></p><p>  // 暫時(shí)更改玩家信息</p><p>  if ( m_Player[i][j][m] )</p>&l

101、t;p><b>  {</b></p><p>  temp1[n] = m;</p><p>  m_Player[i][j][m] = false;</p><p>  temp2[n] = m_Win[0][m];</p><p>  m_Win[0][m] = -1;</p><p>

102、;<b>  n++;</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  ptempTable[i][j] = 0;</p><p><b>  pi = i;</b></p><

103、;p><b>  pj = j;</b></p><p>  while ( SearchBlank( i, j, ptempTable ) )</p><p><b>  {</b></p><p>  ptempTable[i][j] = 2; // 標(biāo)記已被查找</p><p>  st

104、ep.color = m_pTable->GetColor();</p><p>  step.x = i;</p><p>  step.y = j;</p><p>  ptemp = GiveScore( step );</p><p>  if ( pscore > ptemp ) // 此時(shí)為玩家下子,運(yùn)用極小極大法時(shí)應(yīng)

105、選取最小值</p><p>  pscore = ptemp;</p><p><b>  }</b></p><p>  for ( m = 0; m < n; m++ )</p><p><b>  {</b></p><p><b>  // 恢復(fù)玩家信

106、息</b></p><p>  m_Player[pi][pj][temp1[m]] = true;</p><p>  m_Win[0][temp1[m]] = temp2[m];</p><p><b>  }</b></p><p>  6.2.6 選取最佳落子</p><p>

107、  在循環(huán)結(jié)束的時(shí)候,就可以根據(jù)攻、守兩方面的打分綜合地考慮落子位置了。代碼如下:</p><p>  if ( ctemp + pscore > cscore )</p><p><b>  {</b></p><p>  cscore = ctemp + pscore;</p><p>  bestx = pi

108、;</p><p>  besty = pj;</p><p><b>  }</b></p><p>  在這之后,重新改變一下棋盤(pán)的狀態(tài)(6.2.2)即可。</p><p><b>  7 幾點(diǎn)補(bǔ)充說(shuō)明</b></p><p>  考慮到程序的響應(yīng)速度,人機(jī)對(duì)弈算法只對(duì)玩

109、家的棋子進(jìn)行了一步的推測(cè)。</p><p>  由于計(jì)算機(jī)在落子時(shí)選取的是得分最高的一步落子,所以如果玩家在開(kāi)局的時(shí)候不改變落子步驟,那么將會(huì)獲得從頭至尾相同的棋局。</p><p>  考慮到下棋同時(shí)還要聊天,所以并未對(duì)落子時(shí)間加入任何限制,同樣如果玩家離開(kāi)游戲也不會(huì)判負(fù)。</p><p>  對(duì)于人機(jī)對(duì)弈的悔棋處理,由于這個(gè)算法的開(kāi)銷(xiāo)相當(dāng)大,每一步落子都會(huì)存在不

110、同的棋盤(pán)布局,所以實(shí)現(xiàn)從頭到尾的悔棋不是很現(xiàn)實(shí)(將會(huì)存在過(guò)多的空間保存棋盤(pán)布局),因而在人機(jī)對(duì)弈模式下,只允許玩家悔最近的兩步落子。</p><p><b>  8 心得體會(huì)</b></p><p>  通過(guò)編寫(xiě)這個(gè)程序,我體會(huì)最為深刻的一點(diǎn)是系統(tǒng)架構(gòu)和設(shè)計(jì)模式的重要性。即使是對(duì)于一個(gè)并不大的程序,代碼的組織都是非常重要的,因?yàn)檫@關(guān)系到日后的維護(hù)以及擴(kuò)展。這個(gè)游戲之中

111、,有關(guān)網(wǎng)絡(luò)Socket編程或者博弈樹(shù)算法的知識(shí)都可以直接從無(wú)所不包的Internet上獲取,甚至可以直接獲得一個(gè)完整的五子棋人機(jī)對(duì)弈算法的源代碼級(jí)模塊。但是對(duì)于系統(tǒng)的架構(gòu),卻完全是自己的事情,幾千上萬(wàn)行的代碼需要通過(guò)合適的方法組織起來(lái),使程序員編寫(xiě)代碼更加有條理,更加符合軟件工程的標(biāo)準(zhǔn),這才是最重要的。</p><p>  在剛開(kāi)始編寫(xiě)這個(gè)程序的時(shí)候,我幼稚地認(rèn)為其中最重要的是博弈樹(shù)算法。但是頭一個(gè)月編寫(xiě)程序的時(shí)

112、候卻發(fā)現(xiàn)程序越寫(xiě)越不容易維護(hù),可見(jiàn)是我走錯(cuò)了方向。后來(lái)我向公司真正的軟件設(shè)計(jì)人員及系統(tǒng)架構(gòu)師討教,他們告訴我:我們的先人早已為我們準(zhǔn)備好了各種精良可用的現(xiàn)成算法,我們所要做的就是直接“拿來(lái)主義”罷了;但是對(duì)于代碼的組織(也就是軟件的架構(gòu))才是真正軟件工業(yè)的核心部分,因?yàn)檐浖聦?shí)上是直接和經(jīng)濟(jì)掛鉤的,因此我們必須在編寫(xiě)代碼之前選擇一種最為合適的方法來(lái)組織這些代碼,否則我們將會(huì)失去更多的時(shí)間和金錢(qián)。[15]</p><p

113、>  于是,我將以前寫(xiě)的代碼全部刪除,認(rèn)真地思考了三天的時(shí)間。我也在這三天內(nèi)真正從一個(gè)學(xué)生程序員走入了軟件開(kāi)發(fā)的大門(mén),我開(kāi)始發(fā)現(xiàn)其實(shí)軟件開(kāi)發(fā)并不是純數(shù)學(xué)——正相反,數(shù)學(xué)只占了很小的一部分。它其實(shí)是一種哲學(xué),一種有著數(shù)學(xué)美感的哲學(xué)。</p><p><b>  參考文獻(xiàn)</b></p><p>  MSDN for Visual Studio 6.0</p&

114、gt;<p>  設(shè)計(jì)模式——可復(fù)用面向?qū)ο筌浖幕A(chǔ),Erich Gamma/Richard Helm/Ralph Johnson/John Vlissides著,李英軍/馬曉星/蔡敏/劉建中 等譯,機(jī)械工業(yè)出版社</p><p>  深入淺出MFC(第2版),侯俊杰著,華中科技大學(xué)出版社</p><p>  Microsoft® Visual C++.NET 技

115、術(shù)內(nèi)幕(第6版),George Shepherd/David Kruglinski著,潘愛(ài)民譯,清華大學(xué)出版社</p><p>  Visual C++網(wǎng)絡(luò)通信協(xié)議分析與應(yīng)用實(shí)現(xiàn),汪曉平/鐘軍 等編著,人民郵電出版社</p><p>  C++編程思想,Bruce Eckel著,劉宗田/邢大紅/孫慧杰 等譯,機(jī)械工業(yè)出版社</p><p>  21天學(xué)通C++,Je

116、sse Liberty著,康博創(chuàng)作室譯,人民郵電出版社</p><p>  C++標(biāo)準(zhǔn)程序庫(kù),Nicolai M.Josuttis著,侯捷/孟巖 譯,華中科技大學(xué)出版社</p><p>  Windows程序設(shè)計(jì),Charles Petzold著,北京博彥科技發(fā)展有限公司譯,北京大學(xué)出版社</p><p>  Visual C++.NET網(wǎng)絡(luò)編程,易君 編著,中國(guó)鐵

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論