




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
PAGE題目:基于JAVA語言的中國象棋設(shè)計(jì)與實(shí)現(xiàn)
畢業(yè)設(shè)計(jì)(論文)原創(chuàng)性聲明和使用授權(quán)說明原創(chuàng)性聲明本人鄭重承諾:所呈交的畢業(yè)設(shè)計(jì)(論文),是我個(gè)人在指導(dǎo)教師的指導(dǎo)下進(jìn)行的研究工作及取得的成果。盡我所知,除文中特別加以標(biāo)注和致謝的地方外,不包含其他人或組織已經(jīng)發(fā)表或公布過的研究成果,也不包含我為獲得及其它教育機(jī)構(gòu)的學(xué)位或?qū)W歷而使用過的材料。對(duì)本研究提供過幫助和做出過貢獻(xiàn)的個(gè)人或集體,均已在文中作了明確的說明并表示了謝意。作者簽名:日期:指導(dǎo)教師簽名:日期:使用授權(quán)說明本人完全了解大學(xué)關(guān)于收集、保存、使用畢業(yè)設(shè)計(jì)(論文)的規(guī)定,即:按照學(xué)校要求提交畢業(yè)設(shè)計(jì)(論文)的印刷本和電子版本;學(xué)校有權(quán)保存畢業(yè)設(shè)計(jì)(論文)的印刷本和電子版,并提供目錄檢索與閱覽服務(wù);學(xué)??梢圆捎糜坝?、縮印、數(shù)字化或其它復(fù)制手段保存論文;在不以贏利為目的前提下,學(xué)??梢怨颊撐牡牟糠只蛉績?nèi)容。作者簽名:日期:
【摘要】電腦在中國象棋上的運(yùn)用還剛剛起步,盡管國內(nèi)涌現(xiàn)出一大批中國象棋的專業(yè)網(wǎng)站和專業(yè)軟件,但是由于缺乏必要的基礎(chǔ)工作,電腦技術(shù)在中國象棋上的應(yīng)用優(yōu)勢(shì)還無法體現(xiàn)出來,隨著人工智能及計(jì)算機(jī)硬件的發(fā)展,計(jì)算機(jī)象棋程序的水平也不斷地得到提高。本文通過研究中國象棋的國內(nèi)外研究現(xiàn)狀、分析中國象棋的需求和用JAVA語言設(shè)計(jì)中國象棋程序的可行性,同時(shí)根據(jù)國際象棋程序設(shè)計(jì)的一些成功經(jīng)驗(yàn),主要借鑒了位棋盤、Zobrist鍵值等,針對(duì)中國象棋程序設(shè)計(jì)的一系列問題,總結(jié)出一些中國象棋程序的設(shè)計(jì)方法。根據(jù)該方法設(shè)計(jì)出了符合中國象棋行棋和吃子規(guī)則,能夠判斷勝負(fù),能夠?qū)崿F(xiàn)悔棋、重新開始等多種功能,而且界面十分美觀的中國象棋程序,并給出了JAVA語言的實(shí)現(xiàn)方法。關(guān)鍵詞:中國象棋,位棋盤,Zobrist鍵值,著發(fā)生成【Abstract】TheimplementofplayingChineseChessoncomputerhasjuststarted.Althoughlargenumbersofprofessionalwebsitesandprofessionalchesssoftwarearisedindomestic,thelackofnecessarybasicworkcausestheadvantageofcomputertechnologyapplicationsinChinesechesscan’tbereflected.Withthedevelopmentofartificialintelligenceandcomputerhardware,thelevelofcomputerchessprogramcontinuestobeimproved.ThispaperstudiestheresearchstatusofChinesechess,analyzesthedemandofChinesechess,andlearnsthefeasibilityofChinesechessthatisdesignedbyJavalanguage.Atthesametime,thefunctionisdesignedwiththesuccessfulexperienceofchessprogram,suchastheplaceboard,Zobristkeys,etc.ChinesechessprogramissummarizedsomewaystodesignChinesechessprogramforsolvearangeofissues.Followthisways,itdesignsalltherulesandfuntionswhichadapttotherequirementofChinesechess,includingofmovement,judgement,undo,re-startandsoon.TheapplicationgivestheimplementationmethodinJAVAlanguageandbeautifulinterface.Keywords:ChineseChess,bitboard,zobristkeys目錄TOC\o"1-4"\h\z\u1緒論 11.1研究背景 11.2研究意義 11.3預(yù)期目標(biāo) 12分析 32.1需求分析 32.2可行性分析 32.3功能分析 32.4硬件環(huán)境 42.4.1開發(fā)環(huán)境 42.4.2運(yùn)行環(huán)境 43界面設(shè)計(jì)框架 53.1程序的框架 53.2.基本數(shù)據(jù)結(jié)構(gòu)——位棋盤 53.2.1什么是位棋盤 53.2.2位棋盤的作用 63.2.3位棋盤的基本運(yùn)算 63.2.4Java中位棋盤的實(shí)現(xiàn) 63.3.基本數(shù)據(jù)結(jié)構(gòu)——Zobrist鍵值 93.3.1比較局面的方法 93.3.2Zobrist鍵值的工作原理 93.3.3Zobrist鍵值的實(shí)現(xiàn)方法 103.3.4Java中實(shí)現(xiàn)Zobrist鍵值 104系統(tǒng)實(shí)現(xiàn) 124.1著法生成 124.1.1偽合法著法的生成 124.1.2合法著法的生成 174.2算法實(shí)現(xiàn) 204.2.1行棋規(guī)則算法實(shí)現(xiàn) 204.2.2界面功能算法實(shí)現(xiàn) 235結(jié)論 26參考文獻(xiàn) 27附錄 28附錄1算法主程序 28附錄2程序截圖 53外文文獻(xiàn)與翻譯 54致謝 63北京物資學(xué)院2010屆畢業(yè)論文(設(shè)計(jì))PAGE641緒論1.1研究背景計(jì)算機(jī)現(xiàn)在已經(jīng)成為每天工作和生活必不可少的一部分,電子游戲在計(jì)算機(jī)產(chǎn)業(yè)的帶動(dòng)下也逐步深入我們每個(gè)人的娛樂活動(dòng)中,棋牌游戲作為休閑類電子游戲,相對(duì)于角色扮演類游戲和即時(shí)戰(zhàn)略類游戲等其它游戲,具有上手快、游戲時(shí)間短的特點(diǎn),更利于用戶進(jìn)行放松休閑,為人們所喜愛,特別是棋類游戲,方便、快捷、操作簡單,在休閑娛樂中占主要位置。棋類運(yùn)動(dòng)的推廣和發(fā)展是需要靠信息技術(shù)來推動(dòng)的,時(shí)下盛行的國際象棋有兩個(gè)很好的范例,一個(gè)是象棋棋譜編輯和對(duì)弈程序的公共平臺(tái)——WinBoard平臺(tái),另一個(gè)是商業(yè)的國際象棋數(shù)據(jù)庫和對(duì)弈軟件——ChessBase,他們?yōu)閲H象棋愛好者和研究者提供了極大的便利,也極大的促進(jìn)了國際象棋的發(fā)展。國際象棋軟件有著成功的商業(yè)運(yùn)作,已發(fā)展成一種產(chǎn)業(yè)。在設(shè)計(jì)中國象棋軟件過程中,國際象棋軟件有很多值得借鑒的成功經(jīng)驗(yàn)和優(yōu)秀的思想。1.2研究意義我國現(xiàn)在正處于飛速發(fā)展的階段,想要提高我國的國際地位、讓世界更好的了解我國,不僅要依靠經(jīng)濟(jì)和政治的影響,更要注重文化傳播的作用。中國象棋是我國起源最早(最早出現(xiàn)于戰(zhàn)國時(shí)期)、也是我國保存最為完整的棋類運(yùn)動(dòng)之一,他的行棋規(guī)則和棋子、棋盤的設(shè)計(jì)都蘊(yùn)函著豐富的中國文化。中國象棋的藝術(shù)和棋理折射著以儒家思想為正統(tǒng)的東方民族文化精神,深為我國各階層人民喜愛。但是中國象棋在國際上的普及率仍然很低,并因此未被入選2010年廣州亞運(yùn)會(huì)的競賽項(xiàng)目。想要提高中國象棋的知名度和普及率,就必須要有一個(gè)大眾化的中國象棋游戲平臺(tái),電腦游戲無疑是最佳選擇。然而,電腦在中國象棋上的運(yùn)用還剛剛起步,盡管國內(nèi)涌現(xiàn)出一大批中國象棋的專業(yè)網(wǎng)站和專業(yè)軟件,但是由于缺乏必要的基礎(chǔ)工作,電腦技術(shù)在中國象棋上的應(yīng)用優(yōu)勢(shì)還無法體現(xiàn)出來。因此,我們迫切的需要一個(gè)更加基礎(chǔ)、更加實(shí)用的中國象棋對(duì)戰(zhàn)平臺(tái)。1.3預(yù)期目標(biāo)首先進(jìn)行理論的研究,研究JAVA編程的基礎(chǔ),包括JAVA編成的主要步驟及所需要的工具和軟件,熟悉編程軟件后,開始著手進(jìn)行研究,設(shè)計(jì)出論文的主要框架和具體實(shí)現(xiàn)的步驟、目標(biāo)。其次具體的實(shí)現(xiàn)。設(shè)計(jì)出一個(gè)基于JAVA語言的中國象棋對(duì)戰(zhàn)平臺(tái),由于中國象棋比較復(fù)雜,所以主要設(shè)計(jì)出一個(gè)人、人對(duì)戰(zhàn)的平臺(tái),這個(gè)平臺(tái)必須符合中國象棋規(guī)則(包括勝負(fù)、走棋、悔棋、吃子、判斷勝負(fù)等主要功能,各棋子按象棋規(guī)則走動(dòng)),如果時(shí)間允許,可進(jìn)一步實(shí)現(xiàn)一些附加功能,包括美觀的界面、對(duì)戰(zhàn)雙方交流、添加背景音樂等。最后,依據(jù)框架和目標(biāo)編寫代碼,實(shí)現(xiàn)主要功能并且進(jìn)行測(cè)試,直至程序運(yùn)行成功。最終在深入研究理論的基礎(chǔ)上,實(shí)現(xiàn)基于JAVA語言設(shè)計(jì)的中國象棋,做出預(yù)期的完整游戲。2分析2.1需求分析現(xiàn)在全球超過十億臺(tái)計(jì)算機(jī)正在被使用,并且這個(gè)數(shù)目還在逐漸增加,計(jì)算機(jī)已經(jīng)深入到我們生活的各個(gè)方面。而我們使用計(jì)算機(jī)時(shí),游戲所占的比重很大。棋類游戲作為一種簡單易學(xué)的休閑游戲,一直深受廣大群眾的喜愛。JAVA作為一種程序編寫的語言,在軟件市場(chǎng)的影響力快速提高,潛力巨大。因此用JAVA編寫的中國象棋游戲有著很大的開發(fā)潛力。與網(wǎng)絡(luò)游戲相比,單機(jī)游戲有著不可匹敵的簡約性。人們可以隨心所欲的選擇任何時(shí)間進(jìn)行游戲,而且人人對(duì)戰(zhàn)還可以實(shí)現(xiàn)對(duì)戰(zhàn)雙方的直接交流,尤其隨著筆記本電腦的普及,基本上可以隨時(shí)隨地都把它們帶在身邊,在人們離開家或者想玩的時(shí)候,可以不受任何時(shí)間地點(diǎn)限制地玩自己選擇的游戲。2.2可行性分析隨著計(jì)算機(jī)的普及和應(yīng)用,電子游戲已經(jīng)深入到我們生活的各個(gè)方面,利用電子游戲推廣我國文化、增加我國傳統(tǒng)游戲的市場(chǎng)占有率,是將我國文化推向世界的比較便捷的一種方式。中國象棋作為我國保存最完整、最能代表我國古代文化的游戲之一,它的推廣能夠讓世界更加了解中國。JAVA與C++語言非常相近,但JAVA比C++簡單,它拋棄了C++中的一些非必要的功能。用JAVA編寫的中國象棋程序?qū)崿F(xiàn)了人與人的對(duì)弈,符合中國象棋的行棋規(guī)則,界面美觀,能夠激起玩家的興趣,同時(shí)單機(jī)游戲?qū)τ?jì)算機(jī)的環(huán)境要求十分簡單、易于實(shí)現(xiàn)。2.3功能分析打開游戲,鼠標(biāo)所在的功能鍵會(huì)突出顯示,點(diǎn)開新游戲后,原本的“歡迎使用象棋對(duì)弈系統(tǒng)”會(huì)變成提示“紅棋走棋”或“黑棋走棋”。單擊選中的棋子時(shí),該棋子會(huì)不停閃爍,如果符合規(guī)則,則可以移動(dòng)到指定位置。在進(jìn)行人與人之間對(duì)戰(zhàn)時(shí),按照紅先黑后的順序進(jìn)行,并把下棋的每一步過程記錄下來,在對(duì)戰(zhàn)時(shí)能進(jìn)行悔棋功能,對(duì)悔棋次數(shù)沒有限定,玩家可以再玩之前自己約定,增加了游戲的靈活性。在行棋時(shí)依照“馬走日,象走田,車、炮走直線、士在框內(nèi)走斜線,卒未過河是上下走、過河可左右行走且不能回頭,將、帥只能在框內(nèi)行走”等行走規(guī)則,且按照“炮必須隔一個(gè)棋子才能吃棋子,其他棋子按棋子行走規(guī)則的位置實(shí)現(xiàn)吃子”的規(guī)則,完全符合象棋的行棋規(guī)則。2.4硬件環(huán)境2.4.1開發(fā)環(huán)境1、硬件環(huán)境CPU:AMDTurion(tm)64*21.80GH內(nèi)存:DDR1.5G硬盤:80G2、軟件環(huán)境操作系統(tǒng):WINDOWSXP開發(fā)語言:JAVA2.4.2運(yùn)行環(huán)境1、32M以上內(nèi)存,4G以上硬盤。2、MicrosoftWindows9X/NT/vista操作系統(tǒng)。3、800*600或以上的屏幕分辨率。3界面設(shè)計(jì)框架3.1程序的框架從程序的結(jié)構(gòu)上講,大體上可以將引擎部分劃分為四大塊:棋局表示;著法生成;搜索算法;局面評(píng)估。程序的大概的思想是:首先使用一個(gè)數(shù)據(jù)結(jié)構(gòu)來描述棋局信息,對(duì)某一特定的棋局信息由著法生成器生成當(dāng)前下棋方所有合法的著法并依次存入著法隊(duì)列。然后通過搜索算法來逐一讀取著法并調(diào)用局面評(píng)估函數(shù)對(duì)該著法所產(chǎn)生的后繼局面進(jìn)行評(píng)估打分,從中選出一個(gè)最有可能導(dǎo)致走棋方取勝的著法。在搜索的過程中還可以采用一些輔助手段來提高搜索的效率。其過程如下所示(圖1):圖1著法生成3.2.基本數(shù)據(jù)結(jié)構(gòu)——位棋盤3.2.1什么是位棋盤在中國象棋中,棋盤有90個(gè)交叉點(diǎn)。位棋盤其實(shí)就是一個(gè)長度為90位的變量,每個(gè)位對(duì)應(yīng)一個(gè)交叉點(diǎn),用來記錄棋盤上的某些布爾值。在Java中,用3個(gè)int類型數(shù)據(jù)(每個(gè)32位,共96位多余的6位不用)表示一個(gè)位棋盤。3.2.2位棋盤的作用記錄所有棋子位置的位棋盤AllPieces。AllPieces告訴我們棋盤上哪些格子有棋子,哪些沒有。當(dāng)棋子處于最初位置的時(shí)候,“AllPieces”看上去是這個(gè)樣子的(以下描述中,格子的下標(biāo)從0開始):(Hi,89,a9)111111111000000000101010101000000000000000000101010101000000000010000010000000000111111111(Low,0,i0)其最高位對(duì)應(yīng)第89格(a9格,左上角),最低位對(duì)應(yīng)第0格(a8格,右下角)。有子的位對(duì)應(yīng)1,沒有子的位對(duì)應(yīng)0。這樣顯示位棋盤可能更形象一點(diǎn):黑棋111111111000000000010000010101010101000000000000000000101010101000000000010000010000000000111111111紅棋3.2.3位棋盤的基本運(yùn)算1、與(&)01011001————00012、或(|)01011001————11013、異或(^)01011001————11004、取補(bǔ)(~)a=0001,~a=1110。3.2.4Java中位棋盤的實(shí)現(xiàn)位棋盤類的實(shí)現(xiàn)Java中,位棋盤用3個(gè)int型的數(shù)據(jù)表示,最高六位不用。Java中“與、或、非、異或、左位移,右位移(注意,位棋盤的右位移是無符號(hào)位移)”分別是“&、|、^、<<、>>”。代碼摘要(詳細(xì)代碼見附件)及相關(guān)說明如下:publicclassBitBoard{privateintLow,Mid,Hi//用3個(gè)int字段表示位棋盤,最高位Hi的高//6位不用 publicBitBoard(intArg1,intArg2,intArg3){//構(gòu)造函數(shù) Low=Arg1; Mid=Arg2; Hi=Arg3; }publicstaticBitBoardopAnd(BitBoardarg1,BitBoardarg2){//位棋盤的“與”操作,保存結(jié)果。 intlow=arg1.Low&arg2.Low; intmid=arg1.Mid&arg2.Mid; inthi=arg1.Hi&arg2.Hi; returnnewBitBoard(low,mid,hi);}publicstaticBitBoardopOr(BitBoardarg1,BitBoardarg2)//位棋盤的“或”操作,保存結(jié)果。publicstaticBitBoardopXor(BitBoardarg1,BitBoardarg2)//位棋盤的“異或”操作,保存結(jié)果。publicstaticintcount(BitBoardarg)//計(jì)算位棋盤中非零位的個(gè)數(shù)publicstaticBitBoardduplicate(intarg)//復(fù)制位棋盤publicstaticbooleanequals(BitBoardarg1,BitBoardarg2)//位棋盤是否相等(所有90位對(duì)應(yīng)的位相同即//為相等)publicstaticBitBoardleftShift(BitBoardarg,intnum)//位棋盤arg左位移num位publicstaticrightShift(BitBoard,intnum)//位棋盤右位移num位publicstaticintLSB(BitBoardArg)//位棋盤最低非0位的位置(從0開始計(jì)數(shù))publicstaticintMSB(BitBoardArg)//位棋盤最高非0位的位置(從0開始計(jì)數(shù))publicstaticbooleannotZero(BitBoardArg)//是否非“0”。當(dāng)90位中有非0位時(shí)返回true。}位棋盤的初始化某些位棋盤從程序開始運(yùn)行到結(jié)束都不會(huì)改變。例如上面所述的那個(gè)位棋盤數(shù)組“knight[90]”。(他實(shí)際上記錄了當(dāng)“馬”在任意格子上時(shí),它下一步可以走的格子。)這個(gè)數(shù)組將在程序開始執(zhí)行的時(shí)候被初始化并且不再改變。其余的位棋盤將不斷變化。例如“AllPieces”位棋盤。當(dāng)中國象棋棋盤變化時(shí),它也跟著變化。然而,他們的初始化方式相同。對(duì)于諸如knight[90]這樣不變化的位棋盤的初始化,將在“偽著法生成”章節(jié)詳述。此處敘述走棋過程中隨棋局變化的諸多位棋盤的初始化及相關(guān)操作。首先,初始化“BitBoardbitMask[90]”數(shù)組:BitBoardb=newBitBoard(0,0,1);for(intc=0;c<90;c++){mask[c]=BitBoard.leftShift(b,c);}其次,用一個(gè)叫ChessPosition類記錄棋盤上某一狀態(tài)的所有有用信息。它包含了一個(gè)整型數(shù)組intpiece_in_square[90],還包含了一些位棋盤。publicclassChessPosition{intpiece_in_square[90];intplayer;//輪到哪方走棋,2:紅方走,1:黑方走BitBoardallPieces;BitBoardredKing;//紅帥BitBoardblackKing;//黑將BitBoardredRooks;//紅車BitBoardblackRooks;//黑車BitBoardredKnights;//紅馬BitBoardblackKnights;//黑馬BitBoardredCannon;//紅炮BitBoardredCannon;//黑炮BitBoardredBishops;//紅相BitBoardblackBishops;//黑象BitBoardredAdvisor;//紅仕BitBoardblackAdvisor;//黑士BitBoardredPawns;//紅兵BitBoardblackPawns;//黑卒BitBoardredPieces;//所有紅棋子BitBoardblackPieces;//所有黑棋子};初始化“piece_in_square[]”數(shù)組。piece_in_square[0]=RED_ROOK;piece_in_square[1]=RED_KNIGHT;piece_in_square[2]=RED_BISHOP;…piece_in_square[89]=BLACK_ROOK;現(xiàn)在初始化其他一些位棋盤:for(c=0;c<90;c++){switch(piece_in_square[c]){case:RED_ROOKposition.redPieces=BitBoard.opOr(position.redPieces,bitMask[c]);position.redRooksBitBoard.opOr(position.redRooks,bitMask[c]);break;…}}位棋盤的更新當(dāng)棋盤局面變動(dòng)后,某些位棋盤就需要被更新。例如記錄白子所在位置的“WhitePieces”位棋盤。假如我們把h2格的紅炮移動(dòng)到h9格(炮二進(jìn)七),吃掉黑棋的一個(gè)馬,需要更新如下位棋盤:allPiecesredPiecesredCannonsblackpiecesblackKnights首先,要把redPieces,redCannons位棋盤的“h2”位清零,然后把他們的“h9”位置1。/*clearabitwiththe"XOR"operation*/position.allPieces=BitBoard.opXor(position.allPieces,bitMask[h2];position.redPieces=BitBoard.opXor(position.redPieces,bitMask[h2]);position.redCannons=BitBoard.opXor(position.redCannons,bitMask[h2];/*setabitwiththe"OR"operation*/position.redPieces=BitBoard.opOr(position.redPieces,bitMask[h9]);position.redCannons=BitBoard.opOr(position.redCannons,bitMask[h9]);現(xiàn)在我們要將blackPieces和blackKnights位棋盤的h9位清除,因?yàn)槟抢锏暮隈R被吃掉了。/*clearthecapturedpiece*/position.blackPieces=BitBoard.opXor(position.blackPieces,bitMask[h9]);position.blackKnight=BitBoard.opXor(position.blackPieces,bitMask[h9]3.3.基本數(shù)據(jù)結(jié)構(gòu)——Zobrist鍵值3.3.1比較局面的方法在寫中國象棋程序時(shí),需要比較兩個(gè)局面看它們是否相同。如果比較每個(gè)棋子的位置,或許不需要花很多時(shí)間,但是實(shí)戰(zhàn)中每秒種需要做成千上萬次比較,因此這樣會(huì)使比較操作變成瓶頸的。另外,需要比較的局面數(shù)量多得驚人,要存儲(chǔ)每個(gè)棋子的位置,需要占用非常大的空間。一個(gè)解決方案是建立一個(gè)標(biāo)簽,通常是64位。由于64位不足以區(qū)別每個(gè)局面,所以仍然存在沖突的標(biāo)簽,但實(shí)戰(zhàn)中這種情況非常罕見。3.3.2Zobrist鍵值的工作原理Zobrist鍵值的工作原理用Zobrist技術(shù)產(chǎn)生的鍵值,表面上與局面沒什么關(guān)系。如果一個(gè)棋子動(dòng)過了,就會(huì)得到完全不同的鍵值,所以這兩個(gè)鍵值不會(huì)擠在一塊兒或者沖突。當(dāng)把它們用作散列表鍵值的時(shí)候會(huì)非常有效。另一個(gè)優(yōu)點(diǎn)在于,鍵值的產(chǎn)生是可以逐步進(jìn)行的。例如,紅馬在e5格,那么鍵值里一定異或過一個(gè)“zobrist[KNIGHT][RED][E5]”。如果再次異或這個(gè)值,那么根據(jù)異或的工作原理,這個(gè)“馬”就從鍵值里刪除了。這就是說,如果有當(dāng)前局面的鍵值,并且需要把紅馬從e5移到f7,你只要異或一個(gè)“紅馬在e5”的鍵值,把馬從e5格移走,并且異或一個(gè)“紅馬在f7”的鍵值,把紅馬放在f7上。比起從頭開始一個(gè)個(gè)棋子去異或,這樣做可以得到同樣的鍵值。如果要改變著子的一方,只要異或一個(gè)“改變著子方”的鍵值就可以了。用這種方法,可以在搜索根結(jié)點(diǎn)的時(shí)候構(gòu)造一個(gè)Zobrist鍵值,在搜索時(shí)通過走子函數(shù)“MakeMove()”來更新鍵值,一直讓它保持和當(dāng)前局面同步。3.3.3Zobrist鍵值的實(shí)現(xiàn)方法實(shí)現(xiàn)Zobrist必須從多維的64位數(shù)組開始,每個(gè)數(shù)組含有一個(gè)隨機(jī)數(shù)。在Java中,“rand.nextLong()”函數(shù)返回一個(gè)64位的隨機(jī)數(shù)值。這個(gè)函數(shù)用來填滿一個(gè)long型(64位)的三維數(shù)組:棋子的類型、棋子的顏色和棋子的位置:longzobrist[pcMAX][coMAX][sqMAX];程序啟動(dòng)時(shí)就把這個(gè)數(shù)組用隨機(jī)數(shù)填滿。要為一個(gè)局面產(chǎn)生Zobrist鍵值,首先把鍵值設(shè)成零,然后找棋盤上的每個(gè)子,并且讓鍵值跟“zobrist[pc][co][sq]”做異或(通過“^”運(yùn)算符)運(yùn)算。如果局面由紅方走,那么別去動(dòng)它,如果是黑方走,你還要在鍵值上異或一個(gè)64位的隨機(jī)常數(shù)。3.3.4Java中實(shí)現(xiàn)Zobrist鍵值本系統(tǒng)使用一個(gè)key和一個(gè)lock結(jié)合來區(qū)分每個(gè)局面,這樣發(fā)生沖突(即兩個(gè)局面對(duì)應(yīng)的key和lock一樣)的概率幾乎為0。示例代碼及相關(guān)說明如下填充數(shù)組上述的三維數(shù)組現(xiàn)在改變?yōu)槎S(將顏色與棋子兵種類型合并) ……publicstaticlongZobristKeyPlayer;//改變走子方的key publicstaticlongZobristLockPlayer;//改變走子方的lock publicstaticlong[][]ZobristKeyTable=newlong[14][90]; publicstaticlong[][]ZobristLockTable=newlong[14][90]; …… static{ …… zobristGen();} publicstaticvoidzobristGen(){ inti,j; Randomrand=newRandom();longRandSeed; RandSeed=1; rand.setSeed(RandSeed); ZobristKeyPlayer=rand.nextLong(); for(i=0;i<14;i++){ //0:紅帥1:紅仕2:紅相3:紅馬4:紅車5:紅炮6:紅兵 //7:黑將8:黑士9:黑象10:黑馬11:黑車12:黑炮13:黑卒 for(j=0;j<90;j++){ ZobristKeyTable[i][j]=rand.nextLong(); } } ZobristLockPlayer=rand.nextLong(); for(i=0;i<14;i++){ for(j=0;j<90;j++){ ZobristLockTable[i][j]=rand.nextLong(); } } } 移子函數(shù)當(dāng)移動(dòng)(添加、刪除)一個(gè)棋子時(shí),將當(dāng)前局面的Zobrist鍵值與鍵值表中該棋子的鍵值進(jìn)行異或操作,同時(shí)也與改變走子方的鍵值進(jìn)行異或操作。 publicclassChessPosition{ longZobristKey,ZobristLock;//當(dāng)前局面的zobrist鍵值 publicChessPosition{ ……ZobristKey=0;//初始化為0ZobristLock=0;……} ……publicvoidmakeMove(intSquare,intPiece,booleanIsAdd){ …… ZobristKey^=ZobristKeyTable[PieceType][Square];ZobristLock^=ZobristLockTable[PieceType][Square];ZobristKey^=ZobristKeyPlayer;//改變走子方ZobristLock^=ZobristLockPlayer;…… } }4系統(tǒng)實(shí)現(xiàn)4.1著法生成著法生成在不同的象棋引擎中差異較大。我選擇使用位棋盤生成著法的基本原理。之所以用這種方式生成著法,是因?yàn)樯芍ê馁M(fèi)一定的時(shí)間。如果引擎在檢查了一部分著法后發(fā)現(xiàn)了必須走的棋,那它就無需生成余下的棋步了。因此,可能先生成所有吃子的著法,如果沒有滿意的棋再生成余下的著法。國際象棋引擎Crafty(其作者是RobertHyatt博士)使用三個(gè)著法生成函數(shù)。一個(gè)用來生成所有偽合法吃子著法,一個(gè)生成所有偽合法不吃子著法,最后一個(gè)生成所有擺脫被將軍狀態(tài)的著法。注意前兩個(gè)函數(shù)生成的是偽合法的著法。中國象棋的著法生成與此類似,先生成所有偽合法的著法,存入靜態(tài)數(shù)組中。在對(duì)局中可以用“查表”的方式查找生成的偽著法,并對(duì)其合法性作出判斷。這樣可以節(jié)省大量的時(shí)間。4.1.1偽合法著法的生成偽合法著法包含幾類:1、各兵種的不吃子著法;2、各兵種的吃子著法;3、“將”和擺脫“將”的著法。其中,馬、相(象)、兵、帥(將)、仕(士)的吃子著法與其對(duì)應(yīng)的不吃子著法規(guī)則相同。(偽合法著法并不考慮被吃的棋子的顏色——該棋子是對(duì)方的棋子還是己方的棋子,也不考慮該子是否能動(dòng),例如動(dòng)了該子,雙方的帥將會(huì)面。)炮和車的不吃子著法規(guī)則相同,但分為縱向橫向行走兩類。炮的吃子著法分為縱向和橫向兩類,車的吃子著法也分為縱向和橫向兩類。馬和象的著法要考慮蹩馬腿和塞象眼。將軍的著法單獨(dú)作為一類。本程序使用靜態(tài)數(shù)組存儲(chǔ)生成的偽合法著法,先對(duì)其作一些說明。數(shù)組及其下標(biāo)的含義:1、保存帥(將)、仕(士)、相(相)、馬、兵的偽合法靜態(tài)數(shù)組如下:publicstaticfinalint[][]KingMoves=newint[90][8]; publicstaticfinalint[][]AdvisorMoves=newint[90][8]; publicstaticfinalint[][]BishopMoves=newint[90][8]; publicstaticfinalint[][]ElephantEyes=newint[90][4]; publicstaticfinalint[][]KnightMoves=newint[90][12]; publicstaticfinalint[][]HorseLegs=newint[90][8];publicstaticfinalint[][][]PawnMoves=newint[90][2][4];第一個(gè)下標(biāo)說明棋子所在的格,第二個(gè)下標(biāo)含義不盡相同。帥(將)在某個(gè)位置最多有4種走法,例如KingMoves[13][0]=12表示帥在13格(e1格)時(shí)可以走到12格(當(dāng)然,也可以走到14、4、22格,保存到其他幾個(gè)數(shù)組元素中)。第5種(如果前面只有3種著法,則此處是第4種)保存的是非法著法即KingMoves[13][4]=-1,其作用作為查詢算法的“哨兵”,提高查詢算法的速度。為了速度(以位移運(yùn)算取代除法運(yùn)算),第2個(gè)坐標(biāo)值用2的整次方冪。(在后面所講的開局庫和置換表的大小設(shè)置是2的整次方冪也是這個(gè)道理。)兵的走棋規(guī)則需要分顏色,紅色的垂直走棋方向和黑色的垂直走棋方向是相反的。兵最多有三種走棋方法。AdvisorMoves[90][8]保存的是士的著法。BishopMoves[90][8]保存的是相(象)的著法,ElephanEyes[90][4]保存的是相(象)著法對(duì)應(yīng)的塞象眼的位置。KnightMoves和HorseLegs是馬的著法和蹩馬腿的位置。2、車、炮的偽合法著法靜態(tài)數(shù)組如下: publicstaticfinalint[][][]FileNonCapMoves=newint[10][1024][12]; //共十條橫線,FileNonCapMoves[y][bitWordY][index]=newY,進(jìn) publicstaticfinalint[][][]FileRookCapMoves=newint[10][1024][4]; publicstaticfinalint[][][]FileCannonCapMoves=newint[10][1024][4]; publicstaticfinalint[][][]RankNonCapMoves=newint[9][512][12]; //RankNonCapMoves[x][bitWordX][index]=newX,平 publicstaticfinalint[][][]RankRookCapMoves=newint[9][512][4]; publicstaticfinalint[][][]RankCannonCapMoves=newint[9][512][4]; publicstaticfinalint[][]FileNonCapMax=newint[10][1024]; //FileNonCapMax[y][bitwordY]=MaxY//進(jìn)退 publicstaticfinalint[][]FileNonCapMin=newint[10][1024]; //FileNonCapMax[y][bitwordY]=MinY publicstaticfinalint[][]FileRookCapMax=newint[10][1024]; publicstaticfinalint[][]FileRookCapMin=newint[10][1024]; publicstaticfinalint[][]FileCannonCapMax=newint[10][1024]; publicstaticfinalint[][]FileCannonCapMin=newint[10][1024]; publicstaticfinalint[][]RankNonCapMax=newint[9][512];//平 publicstaticfinalint[][]RankNonCapMin=newint[9][512]; publicstaticfinalint[][]RankRookCapMax=newint[9][512]; publicstaticfinalint[][]RankRookCapMin=newint[9][512]; publicstaticfinalint[][]RankCannonCapMax=newint[9][512]; publicstaticfinalint[][]RankCannonCapMin=newint[9][512];車、炮吃子著法與它們的不吃子著法規(guī)則不同,因此需要分開保存。再將著法分為水平和垂直兩種(也就是進(jìn)、退與平)。車炮的不吃子著法是相同的,因此,分別保存到FileNonCapMoves[10][1024][12]和RankNonCapMoves[9][512][12]中。棋盤的橫線合縱線分別有10條和9條,這就是數(shù)組第一個(gè)下標(biāo)10和9的含義,用來指示車炮在哪條橫線或縱線上。第二個(gè)坐標(biāo)的含義,以橫線走法示例如下:例如,第二條橫線上的棋子如下(有棋子的用1表示,炮或車的位置用x表示,實(shí)際上x也是1): 001100x01那么, RankNonCapMoves[2][101][0]=-1 RankNonCapMoves[2][101][1]=1 RankNonCapMoves[2][101][2]=2 RankNonCapMoves[2][101][3]=0上面的下標(biāo)101就是001100101對(duì)應(yīng)的二進(jìn)制值,數(shù)組元素的值-1、1、2表示可行走格子的增量。 RankRookCapMoves[2][101][0]=-2 RankRookCapMoves[2][101][1]=3RankRookCapMoves[2][101][2]=0以上是車吃子的走法。下面是炮吃子的著法: RankCannonCapMoves[2][101][0]=-2 RankCannonCapMoves[2][101][1]=4 RankCannonCapMoves[2][101][2]=0;下面是最大的位移量和最小的位移量,用來生成合法著法時(shí)初步判斷著法的合法性:RankNonCapMax[2][101]=2//不吃子著法中最大的格子增量RankNonCapMin[2][101]=-1//不吃子著法中最小的格子增量RankRookCapMax[2][101]=3//車吃子著法中最大的格子增量RankRookCapMin[2][101]=-2//車吃子著法中最小的格子增量RankCannonCapMax[2][101]=4//炮吃子著法中最大的格子增量RankCannonCapMin[2][101]=-2//炮吃子著法中最小的格子增量以上是橫向(平)著法的靜態(tài)數(shù)組,縱向著法的表示與此類似,在此不再贅述。3、“照將”著法 publicstaticfinalBitBoard[]CheckLegs=newBitBoard[18];//帥將每個(gè)位置蹩馬腿的位棋盤 publicstaticfinalBitBoard[][]KnightPinCheck=newBitBoard[18][256]; //除去蹩腿位置有子的將軍位置 publicstaticfinalBitBoard[][]FileRookCheck=newBitBoard[18][1024]; //車縱線照將 publicstaticfinalBitBoard[][]FileCannonCheck=newBitBoard[18][1024]; //炮縱線照將 publicstaticfinalBitBoard[][]RankRookCheck=newBitBoard[18][512]; //車橫線照將 publicstaticfinalBitBoard[][]RankCannonCheck=newBitBoard[18][512]; //炮縱線照將 publicstaticfinalBitBoard[]PawnCheck=newBitBoard[18]; //兵照將帥、將的位置共有18個(gè),每個(gè)位置有一個(gè)編號(hào),從0到17,對(duì)應(yīng)數(shù)組的第一個(gè)下標(biāo)。KnightPinCheck是馬“照將”的著法,CheckLegs是馬“照將”蹩馬腿的位棋盤。算法示例——車炮的偽合法著法生成:以下是車炮橫線—縱移(橫線定位,縱向移動(dòng))的算法: //GenerateFilePreMoveforRooksandCannons for(i=0;i<10;i++){//10條橫線 for(j=0;j<1024;j++){//一條縱線位棋盤的二進(jìn)制值 Index=0;//著法種類下標(biāo) FileNonCapMax[i][j]=i; for(k=i+1;k<=9;k++){ if((j&(1<<k))!=0){ break; } FileNonCapMoves[i][j][Index]=k; Index++; FileNonCapMax[i][j]=k; } FileNonCapMin[i][j]=i; for(k=i-1;k>=0;k--){ if((j&(1<<k))!=0){ break; } FileNonCapMoves[i][j][Index]=k; Index++; FileNonCapMin[i][j]=k; } FileNonCapMoves[i][j][Index]=-1; Index=0; FileRookCapMax[i][j]=i; for(k=i+1;k<=9;k++){ if((j&(1<<k))!=0){ FileRookCapMoves[i][j][Index]=k; Index++; FileRookCapMax[i][j]=k; break; } } FileRookCapMin[i][j]=i; for(k=i-1;k>=0;k--){ if((j&(1<<k))!=0){ FileRookCapMoves[i][j][Index]=k; Index++; FileRookCapMin[i][j]=k; break; } } FileRookCapMoves[i][j][Index]=-1; Index=0; FileCannonCapMax[i][j]=i; for(k=i+1;k<=9;k++){ if((j&(1<<k))!=0){ k++; break; } } for(;k<=9;k++){ if((j&(1<<k))!=0){ FileCannonCapMoves[i][j][Index]=k; Index++; FileCannonCapMax[i][j]=k; break; } } FileCannonCapMin[i][j]=i; for(k=i-1;k>=0;k--){ if((j&(1<<k))!=0){ k--; break; } } for(;k>=0;k--){ if((j&(1<<k))!=0){ FileCannonCapMoves[i][j][Index]=k; Index++; FileCannonCapMin[i][j]=k; break; } } FileCannonCapMoves[i][j][Index]=-1; } }4.1.2合法著法的生成合法著法的生成,是在已生成的偽合法著法的基礎(chǔ)之上,增加一些判斷合法性的條件。例如,判斷炮吃子的偽合法著法是否是合法著法,需要判斷被吃子的顏色,同時(shí)需要判斷己方是否正在被“將”,如果正在被“將”,炮吃子是否能解除被“將”的狀態(tài)?,F(xiàn)列出生成合法著法的算法并附簡要說明如下:偽合法著法的合法性判斷:以炮為例,算法如下: publicbooleanLeagalMove(MoveStructMove){ intPiece,Attack,x,y,BitWord; Piece=Squares[Move.src]; if((Piece&(Player!=0?32:16))==0){ returnfalse;//所選的棋子是否是當(dāng)前Player的 } Attack=Squares[Move.dst];//被攻擊的棋子 if((Attack&(Player!=0?32:16))!=0){ returnfalse;//有被攻擊的棋子,但不是對(duì)方的。 } switch(PieceTypes[Piece]-(Player!=0?7:0)){//判斷棋子類型 case5://炮,吃子時(shí)中間要有炮架 x=File[Move.src];//棋子所在的列 y=Rank[Move.src];//棋子所在的行 if(x==File[Move.dst]){//與目標(biāo)位置在同一列,也就是進(jìn)退 BitWord=BitFiles[x];//該列的二進(jìn)制位棋盤數(shù)值,共十位 if(Move.src<Move.dst){//進(jìn) if((Attack&(Player!=0?16:32))!=0){//吃子returnMove.dst==PreMoves.FileCannonCapMax[y][BitWord]+Bottom[x]; }else{//不吃子 returnMove.dst<=PreMoves.FileNonCapMax[y][BitWord]+Bottom[x]; } }else{//Move.Src>Move.Dst,退 if((Attack&(Player!=0?16:32))!=0){ returnMove.dst==PreMoves.FileCannonCapMin[y][BitWord]+Bottom[x]; }else{ returnMove.dst>=PreMoves.FileNonCapMin[y][BitWord]+Bottom[x]; } } }else{//與目標(biāo)位置的列位置不同,也就是“平” BitWord=BitRanks[y];//行位棋盤數(shù)值,9位二進(jìn)制數(shù) if(Move.src<Move.dst){ if((Attack&(Player!=0?16:32))!=0){ returnMove.dst==PreMoves.RankCannonCapMax[x][BitWord]+y; }else{ returnMove.dst<=PreMoves.RankNonCapMax[x][BitWord]+y; } }else{ if((Attack&(Player!=0?16:32))!=0){ returnMove.dst==PreMoves.RankCannonCapMin[x][BitWord]+y; }else{ returnMove.dst>=PreMoves.RankNonCapMin[x][BitWord]+y; } } }以上對(duì)炮偽合法著法的合法性判斷。File[90]和Rank[90]保存的是格子對(duì)應(yīng)的列和行,這比“%、/”(取余和除法)的運(yùn)算速度快。BitFiles[9]和BitRanks[10]分別保存的是位棋盤中9列(每列共10位)和10行(每行共9位)的二進(jìn)制值。PreMoves是生成偽合法的類,保存有所有偽合法著法的靜態(tài)數(shù)組。合法著法的生成 代碼如下: publicclassMoveStruct{ publicintsrc,cap,dst;//位置a0=0,b0=10 publicbooleanchk; publicMoveStruct(){ src=dst=cap=-1; chk=false; } publicMoveStruct(ints,intd){ src=s;dst=d; chk=false; } publicMoveStruct(StringmoveStr){ move(moveStr);chk=false; } publicvoidmove(StringmoveStr){src=(char)(ChessPosition.Bottom[moveStr.charAt(0)-'a']+moveStr.charAt(1)-'0');dst=(char)(ChessPosition.Bottom[moveStr.charAt(2)-'a']+moveStr.charAt(3)-'0');if(src<0||src>=90||dst<0||dst>=90){//invalidmove src=dst=-1; } }}MoveStruct是著法的數(shù)據(jù)結(jié)構(gòu),src和dst分別是移動(dòng)前后的位置(格子) publicvoidGenMoves(finalChessPositionPosition,finalintHistTab[][]){ GenKingMoves(Position,HistTab);//帥將 GenAdvisorMoves(Position,HistTab);//仕士 GenBishopMoves(Position,HistTab);//相象 GenKnightMoves(Position,HistTab);//馬 GenRookMoves(Position,HistTab);//車 GenCannonMoves(Position,HistTab);//炮 GenPawnMoves(Position,HistTab);//兵 }GenMoves根據(jù)當(dāng)前局面(作為參數(shù)的finalChessPositionPosition)生成合法著法,并保存在一個(gè)數(shù)組MoveStructmoveList[MAX_MOVENUM]中,同時(shí)也將每個(gè)著法的局面評(píng)價(jià)值存入數(shù)組intvalueList[MAX_MOVENUM]中,這樣以便對(duì)著法進(jìn)行排序,在搜索算法中提高算法的效率。以上算法調(diào)用的子函數(shù)再此給出為代碼,詳細(xì)代碼見附件。GenKnightMoves(ChessPositionPosition,HistTab){ 根據(jù)Position,得出當(dāng)前局面player馬的偽合法著法; for(all馬的偽合法著法){ if(ChessPosition.LeagalMove(其中一個(gè)著法)){ ChessPosition.MakeMove(); If(走子方不是處于被“將”狀態(tài)) saveToMoveList; ChessPosition.UnMove();} }}4.2算法實(shí)現(xiàn)4.2.1行棋規(guī)則算法實(shí)現(xiàn)走棋的算法實(shí)現(xiàn)在中國象棋中,由于各個(gè)棋子都有自己的行棋規(guī)則,所以棋子走法算法非常復(fù)雜。本文中,利用數(shù)組來記錄棋子的位置,并依據(jù)數(shù)組中X,Y坐標(biāo)的改變來改變棋子在棋盤中的位置。下面我以卒的算法為例,介紹如何實(shí)現(xiàn)棋子按行棋規(guī)則行走。在卒移動(dòng)算法中,將卒的移動(dòng)分為向前、向左、向右三部分。當(dāng)程序執(zhí)行到該算法時(shí),首先根據(jù)棋子的位置,判斷是紅棋還是黑棋,我們以黑棋為例,當(dāng)卒想要移動(dòng)時(shí),程序需要判斷棋子距離目標(biāo)位置是否為一步距離,同時(shí)判斷所作的移動(dòng)是什么性質(zhì)。如果是向下,距離也是一步,可以通過Y坐標(biāo)加一的方式移動(dòng)棋子,若果是向左右移動(dòng),就需要在判斷移動(dòng)距離的同事判斷是否已經(jīng)過河,如果符合規(guī)則,可以通過X坐標(biāo)的加減來實(shí)現(xiàn)。在移動(dòng)的同時(shí),還要將當(dāng)前棋子的位置記錄下來,以便悔棋。具體算法如下: if((me.getY()-play.getY())>27&&(me.getY()-play.getY())<86&&(me.getX()-play.getX())<55&&(me.getX()-play.getX())>0){ Var.add(String.valueOf(play.isVisible())); Var.add(String.valueOf(play.getX())); Var.add(String.valueOf(play.getY())); Var.add(String.valueOf(Man)); play.setBounds(play.getX(),play.getY()+57,55,55); }elseif(play.getY()>284&&(me.getX()-play.getX())>=57&&(me.getX()-play.getX())<=112){ play.setBounds(play.getX()+57,play.getY(),55,55); } elseif(play.getY()>284&&(play.getX()-me.getX())>=2&&(play.getX()-me.getX())<=58){ play.setBounds(play.getX()-57,play.getY(),55,55); } }吃子的算法實(shí)現(xiàn)在象棋中,除棋子炮外,其他棋子吃子算法都與行棋算法比較相像,只是多了一步吃子的操作,而在執(zhí)行炮吃子時(shí),還需要添加一步中間是否有子的判斷,下面,我介紹一下炮吃子的規(guī)則。在炮吃子時(shí),需要定義一個(gè)變量,記錄起點(diǎn)和終點(diǎn)間是否有子。同時(shí)要定義一個(gè)循環(huán),用于查找所有棋子所在的位置。這樣在執(zhí)行循環(huán)的時(shí)候,就可以找出所有與自己在一條直線上的棋子,同時(shí)記錄下炮和目標(biāo)棋子中間是否有一個(gè)棋子。如果這些規(guī)則都符合,且目標(biāo)子與炮的顏色不相同,目標(biāo)子將被設(shè)置為不可見,且炮會(huì)占據(jù)目標(biāo)子的位置,這就完成了吃子的目的。 publicvoidcannonRule(intChess,JLabelplay,JLabelplayTake,JLabelplayQ[],MouseEventme){ intCount=0; for(intj=0;j<32;j++){ if(playQ[j].getX()-play.getX()>=-27&&playQ[j].getX()-play.getX()<=27&&playQ[j].getName()!=play.getName()&&playQ[j].isVisible()){ //自己是起點(diǎn)被吃的是終點(diǎn)(以從上到下為例) for(intk=play.getY()+57;k<playTake.getY();k+=57){ //大于起點(diǎn)、小于終點(diǎn)的坐標(biāo)就可以知道中間是否有棋子 if(playQ[j].getY()<playTake.getY()&&playQ[j].getY()>play.getY()){ //計(jì)算起點(diǎn)和終點(diǎn)的棋子個(gè)數(shù) Count++; break; } }//炮吃子時(shí),與目標(biāo)間要一個(gè)棋子,并規(guī)定目標(biāo)與自己不能同色 if(Count==1&&Chess==0&&playTake.getName().charAt(1)!=play.getName().charAt(1)){ //當(dāng)前記錄添加到集合(用于悔棋) Var.add(String.valueOf(play.isVisible())); Var.add(String.valueOf(play.getX())); Var.add(String.valueOf(play.getY())); Var.add(String.valueOf(Man)); //當(dāng)前記錄添加到集合(用于悔棋) Var.add(String.valueOf(playTake.isVisible())); Var.add(String.valueOf(playTake.getX())); Var.add(String.valueOf(playTake.getY())); Var.add(String.valueOf(i));//如果符合規(guī)則,則目標(biāo)子將自己的位置釋放,即被吃掉 playTake.setVisible(false);//將炮的位置移動(dòng)到目標(biāo)子的位置 play.setBounds(playTake.getX(),playTake.getY(),55,55); } }//炮、車吃棋方法結(jié)束4.2.1.在中國象棋中,將是最重要的棋子,它的存在決定了棋局的勝負(fù)。本文判斷勝負(fù)的算法正是基于這個(gè)思想,如果紅棋的將不可見了,則黑棋贏得比賽,如果黑棋的將不可見了,則紅棋贏得比賽,系統(tǒng)將彈出提示對(duì)話框,并且此時(shí)將不能再走棋,具體算法如下: if(!play[31].isVisible()){ JOptionPane.showConfirmDialog( this,"黑棋勝利","玩家一勝利", JOptionPane.DEFAULT_OPTION,JOptionPane.WARNING_MESSAGE); //雙方都不可以在走棋了 chessPlayClick=3; text.setText("黑棋勝利"); }//if elseif(!play[30].isVisible()){ JOptionPane.showConfirmDialog( this,"紅棋勝利","玩家二勝利", JOptionPane.DEFAULT_OPTION,JOptionPane.WARNING_MESSAGE); chessPlayClick=3; text.setText("紅棋勝利"); }//elseif 4.2.2界面功能算法實(shí)現(xiàn)悔棋功能的實(shí)現(xiàn)本設(shè)計(jì)設(shè)置了悔棋按鈕,玩家可以依據(jù)自己的需要悔棋,沒有次數(shù)的限制,悔棋按鈕是通過記錄坐標(biāo)的方式執(zhí)行悔棋的,具體算法如下: elseif(ae.getSource().equals(repent)){ try{ //獲得setVisible屬性值 StringS=(String)Var.get(Var.size()-4); //獲得X坐標(biāo) intx=Integer.parseInt((String)Var.get(Var.size()-3)); //獲得Y坐標(biāo) inty=Integer.parseInt((String)Var.get(Var.size()-2)); //獲得索引 intM=Integer.parseInt((String)Var.get(Var.size()-1)); //賦給棋子 play[M].setVisible(true); play[M].setBounds(x,y,55,55); if(play[M].getName().charAt(1)=='1'){ text.setText("黑棋走棋"); chessPlayClick=1; } else{ text.setText("紅棋走棋"); chessPlayClick=2; } //刪除用過的坐標(biāo) Var.remove(Var.size()-4); Var.remove(Var.size()-3); Var.remove(Var.size()-2); Var.remove(Var.size()-1); //停止旗子閃爍 chessManClick=false; } catch(Exceptione){ } }恢復(fù)初始狀態(tài)功能的實(shí)現(xiàn)該程序設(shè)置了“新游戲”按鈕,點(diǎn)擊這個(gè)按鈕,則無論棋局進(jìn)行到什么狀態(tài),都會(huì)恢復(fù)到初始狀態(tài),重新開始游戲?!靶掠螒颉卑粹o的具體算法思想是:當(dāng)點(diǎn)擊這個(gè)按鈕時(shí),程序?qū)⒄{(diào)用棋子排列的函數(shù),重新排列棋子的位置,方法是定義通過兩個(gè)變量,來設(shè)置棋子的位置,同時(shí)將悔棋功能中的記錄清空,以恢復(fù)初始的狀態(tài)。具體算法如下(以黑棋為例): publicvoid
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 大學(xué)生體像認(rèn)知與醫(yī)學(xué)美容態(tài)度的關(guān)系調(diào)查
- 山東省濟(jì)南市2024-2025學(xué)年高三上學(xué)期期末學(xué)習(xí)質(zhì)量檢測(cè)英語試題【含答案】
- 室內(nèi)廚房設(shè)計(jì)施工方案
- 挖碴裝車施工方案
- 地坪施工訂做方案范本
- 5年級(jí)學(xué)霸數(shù)學(xué)筆記
- 2025年規(guī)劃數(shù)學(xué)試題及答案
- 等邊三角形電荷電場(chǎng)線
- c.d級(jí)危房安全風(fēng)險(xiǎn)隱患問題及短板
- 接口處防水施工方案
- 機(jī)械工程原理真題集
- 2025年甘肅甘南州國控資產(chǎn)投資管理集團(tuán)有限公司面向社會(huì)招聘工作人員12人筆試參考題庫附帶答案詳解
- 2025年內(nèi)蒙古北方職業(yè)技術(shù)學(xué)院單招職業(yè)傾向性測(cè)試題庫及答案一套
- 2025年安徽水利水電職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測(cè)試題庫(含答案)
- 中國瓶裝水飲用水項(xiàng)目投資可行性研究報(bào)告
- 《心肌缺血心電圖》課件
- 2025年中國建筑股份有限公司招聘筆試參考題庫含答案解析
- 持續(xù)葡萄糖監(jiān)測(cè)臨床應(yīng)用專家共識(shí)2024解讀
- 《胸部影像疾病診斷》課件
- DB33T 2157-2018 公共機(jī)構(gòu)綠色數(shù)據(jù)中心建設(shè)與運(yùn)行規(guī)范
- 健康促進(jìn)機(jī)關(guān)創(chuàng)建培訓(xùn)
評(píng)論
0/150
提交評(píng)論