C語言游戲2五子棋人機(jī)對戰(zhàn)_第1頁
C語言游戲2五子棋人機(jī)對戰(zhàn)_第2頁
C語言游戲2五子棋人機(jī)對戰(zhàn)_第3頁
C語言游戲2五子棋人機(jī)對戰(zhàn)_第4頁
C語言游戲2五子棋人機(jī)對戰(zhàn)_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

五子棋人機(jī)?對戰(zhàn),AI很低,做參考用,僅僅為大家?提供一下思?路。開發(fā)環(huán)境:Visua?lC++6.0游戲界面:C語言游戲?2-五子棋(人機(jī)對戰(zhàn))TOC\o"1-2"\h\z\uHYPER?LINK一、開始工作 PAGER?EF_Toc3?39626?683\h2HYPER?LINK二、畫圖 PAGER?EF_Toc3?39626?684\h5HYPER?LINK三、下棋 PAGER?EF_Toc3?39626?685\h8HYPER?LINK四、判斷勝負(fù) PAGER?EF_Toc3?39626?686\h10HYPER?LINK五、人工智能 PAGER?EF_Toc3?39626?687\h13HYPER?LINK六、附加功能 PAGER?EF_Toc3?39626?688\h17一、開始工作新建工程,選MFCAppWi?zard(exe),添上工程名?,確定。選基于對話?框,完成,確定。插入位圖網(wǎng)上的源碼?一般都是將?棋盤和棋子?用畫圖程序?畫出來,但我不會弄?。我的方法是?直接貼圖。先插入位圖?(BMP格式?),以下是我用?的位圖,當(dāng)然你也可?以用自己的?位圖:插入位圖流?程:有時會彈出?下面這個窗?口,這是完全沒?有問題的:位圖插入后?會自動賦予?ID值,我們可以修?改一下:二、畫圖///////////////////////////Draw函數(shù)/////////////////////////////////////////添加成員函?數(shù)Draw?:Draw(intx,inty,UINTbitma?p,CDC*pDC)解釋一下:x,y是畫圖的?坐標(biāo)bitma?p是圖片I?D,比如我的黑?棋圖片ID?就是IDB?_BLAC?KpDC是顯?示圖片窗口?的句柄我的畫圖函?數(shù)是下面這?樣的,其中要注意?兩個函數(shù)B?itBlt?和Tran?spare?ntBlt?,程序后有解?釋:voidCMyDl?g::Draw(intx,inty,UINTbitma?p,CDC*pDC){ //裝載圖片 CBitm?apm_bmp?; m_bmp?.LoadB?itmap?(bitma?p); //創(chuàng)建畫布,比如要在窗?口顯示,則pDC為?窗口句柄 CDCdc; dc.Creat?eComp?atibl?eDC(pDC); //將位圖選到?dc中,順便保存畫?刷到pOl?dbmp //保存畫刷、恢復(fù)畫刷為?規(guī)范操作,但可以不用? CBitm?ap*pOldb?mp=dc.Selec?tObje?ct(&m_bmp?); //創(chuàng)建bm,用來獲取圖?片信息,這里是為了?獲取圖片尺?寸 BITMA?Pbm; m_bmp?.GetOb?ject(sizeo?f(BITMA?P),&bm); //畫圖 if(IDB_B?OARD==bitma?p)//畫棋盤 pDC->BitBl?t(x,y,bm.bmWid?th,bm.bmHei?ght,&dc,0,0,SRCCO?PY); else {//每個圖片里?有4X4個?棋子,我只要畫出?一個就行了? intw=bm.bmWid?th/4; inth=bm.bmHei?ght/4; Trans?paren?tBlt(pDC->m_hDC?,x,y,w,h,dc.m_hDC?,0,0,w,h,RGB(255,255,255)); } dc.Selec?tObje?ct(pOldb?mp);//恢復(fù)畫刷}pDC->BitBl?t(x,y,bm.bmWid?th,bm.bmHei?ght,&dc,0,0,SRCCO?PY);功能是貼圖?:將dc中的?位圖,截取大小b?m.bmWid?th,bm.bmHei?ght,粘貼到pD?C所指的設(shè)?備,貼圖坐標(biāo)x?,y。最后一個參?數(shù)為粘貼方?式,我們是直接?粘貼,所以是SR?CCOPY?Trans?paren?tBlt(pDC->m_hDC?,x,y,w,h,dc.m_hDC?,0,0,w,h,RGB(255,255,255));功能也是貼?圖,但圖片背景?透明:將dc中的?位圖(dc.m_hDC?是dc的句?柄),截取大小w?,h,粘貼到pD?C所指的設(shè)?備,貼圖坐標(biāo)x?,y,貼圖大小為?w,h,如果圖片大?小不符則拉?伸或壓縮圖?片。最后一項(xiàng)是?背景色,可以將圖片?背景透明化?。使用Tra?nspar?entBl?t必須包含?頭文件和類?庫,否則編譯錯?誤:#inclu?de<wingd?i.h>#pragm?acomme?nt(lib,"msimg?32.lib")函數(shù)弄好后?就調(diào)用這個?函數(shù)畫圖了?。先在OnI?nitDi?alog函?數(shù)中加入以?下代碼,調(diào)整對話框?大小,并隱藏按鈕?: //TODO:Addextra?initi?aliza?tionhere MoveW?indow?(0,0,520,540);//窗口定位 Cente?rWind?ow(); //居中窗口 GetDl?gItem?(IDOK)->ShowW?indow?(SW_HI?DE); GetDl?gItem?(IDCAN?CEL)->ShowW?indow?(SW_HI?DE);或者直接在?資源窗口中?調(diào)整對話框?:然后在On?Paint?函數(shù)中加入?以下代碼畫?圖: CDC*pDC=GetDC?();//獲取當(dāng)前窗?口句柄 Draw(13,13,IDB_B?OARD,pDC);//畫棋盤 //Draw(0,0,IDB_B?LACK,pDC);//畫黑棋,只是為了查?看顯示效果?調(diào)整一下界?面,希望你沒有?強(qiáng)迫癥,可不要在調(diào)?整上花太多?時間了。下面是我做?出的效果:三、下棋現(xiàn)在要將棋?子準(zhǔn)確下到?各個點(diǎn)上,我用的棋盤?,間距為34?,點(diǎn)擊鼠標(biāo)時?獲取點(diǎn)擊坐?標(biāo)x,y,然后x/34,y/34,確定棋子下?到了哪個點(diǎn)?上。////////////////////////OnLBu?ttonU?p函數(shù)///////////////////////////////////添加消息處?理函數(shù):我用的消息?是WM_L?BUTTO?NUP,也就是當(dāng)鼠?標(biāo)左鍵抬起?來的時候,函數(shù)響應(yīng):以下是函數(shù)?代碼:voidCMyDl?g::OnLBu?ttonU?p(UINTnFlag?s,CPoin?tpoint?){ //TODO:Addyourmessa?gehandl?ercodehereand/orcalldefau?lt if(point?.x>0&&point?.x<480&&point?.y>0&&point?.y<480) { intj=point?.x/34; inti=point?.y/34; intx=j*34; inty=i*34; CDC*pDC=GetDC?();//獲取當(dāng)前設(shè)?備句柄 Draw(x,y,IDB_B?LACK,pDC); } CDial?og::OnLBu?ttonU?p(nFlag?s,point?);}函數(shù)中,point?.x,point?.y為點(diǎn)擊鼠?標(biāo)時的坐標(biāo)?現(xiàn)在可以將?棋子準(zhǔn)確地?下到點(diǎn)上了?,可是就算點(diǎn)?上有已經(jīng)有?棋子了,點(diǎn)鼠標(biāo)后也?會下棋。所以我們用?一個二維數(shù)?組存儲棋盤?上的棋子。添加成員變?量:初始化成員?變量,在OnPa?int函數(shù)?里加入下面?代碼。畫完棋盤的?同時,初始化棋盤?。for(inti=0;i<15;i++) for(intj=0;j<15;j++) chess?[i][j]=0;修改OnL?Butto?nUp函數(shù)?中的下棋代?碼原來是直?接用Dra?w(x,y,IDB_B?LACK,pDC);畫棋,現(xiàn)在改成下?面的內(nèi)容,當(dāng)點(diǎn)上沒有?棋時才下棋?: if(0==chess?[i][j]) { Draw(x,y,IDB_B?LACK,pDC); chess?[i][j]=1;//下的黑棋,這一點(diǎn)變成?1 }下棋功能完?成了。四、判斷勝負(fù)////////////////////////////iswin?函數(shù)/////////////////////////////////////////先添加一個?BOOL類?型的成員函?數(shù)iswi?n(inti,intj),每下一個棋?子都通過這?個棋子判斷?是否贏了。是則返回T?RUE(或1),否則返回F?ALSE(或0)。默認(rèn)返回F?ALSE。在OnLB?utton?Up函數(shù)中?調(diào)用isw?in。如果贏了彈?出窗口"我贏了,結(jié)束戰(zhàn)斗!",初始化棋盤?:voidCMyDl?g::OnLBu?ttonU?p(UINTnFlag?s,CPoin?tpoint?){ //TODO:Addyourmessa?gehandl?ercodehereand/orcalldefau?lt if(point?.x>0&&point?.x<480&&point?.y>0&&point?.y<480) { intj=point?.x/34; inti=point?.y/34; intx=j*34; inty=i*34; CDC*pDC=GetDC?();//獲取當(dāng)前設(shè)?備句柄 if(0==chess?[i][j]) { Draw(x,y,IDB_B?LACK,pDC); chess?[i][j]=1; } //判斷輸贏 if(iswin?(i,j)) { Messa?geBox?("我贏了,結(jié)束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } } CDial?og::OnLBu?ttonU?p(nFlag?s,point?);}Messa?geBox?彈出窗口"我贏了,結(jié)束戰(zhàn)斗!"Inval?idate?(FALSE?)會放出一個?WM_PA?INT消息?,間接調(diào)用O?nPain?t函數(shù),初始化棋盤?。/////////////////////////////searc?h函數(shù)//////////////////////////////////////那到底怎么?判斷輸贏呢??我采用的是?下面這個方?法:申明變量a?live1?,alive?2,用來判斷活?棋還是死棋?。申明變量c?ount用?來判斷連子?的個數(shù)。以橫向四子?為例,我剛下了第?三個棋子。先從第三個?棋子位置開?始,往右邊掃描?,如果下的也?是黑棋,則coun?t++。如果遇到的?不是黑棋,判斷是不是?空地。如果是空地?alive?1=1,表示右邊一?頭是活的。否則ali?ve=0。然后回到第?三子位置,往左邊掃描?。對于掃描,我這里添加?一個成員函?數(shù)sear?ch用來掃?描代碼比較長?,注意不要出?錯了,不然調(diào)試很?麻煩的。intCMyDl?g::searc?h(inti,intj,intm,intn){ inttempi?,tempj?,count?=-1; intalive?1=0,alive?2=0; //第一次掃描? tempi?=i;tempj?=j; while?(tempi?>0&&tempi?<15&& tempj?>0&&tempj?<15&& chess?[tempi?][tempj?]==chess?[i][j]) { tempi?+=m;tempj?+=n; count?++; } if(chess?[tempi?][tempj?]==0)alive?1=1; //第二次掃描? tempi?=i;tempj?=j; while?(tempi?>0&&tempi?<15&& tempj?>0&&tempj?<15&& chess?[tempi?][tempj?]==chess?[i][j]) { tempi?-=m;tempj?-=n; count?++; } if(chess?[tempi?][tempj?]==0)alive?2=1; if(count?>=5)retur?n5; elseif(alive?1&&alive?2)retur?ncount?; elseif((alive?1||alive?2)&&count?!=1)retur?ncount?+4; retur?n0;}函數(shù)的參數(shù)?i,j是下棋的?位置,m,n表示掃描?的方向。比如從左下?角往右上角?掃描,坐標(biāo)上是x?+1,y-1,對應(yīng)的n=1,m=-1(x對應(yīng)的是?j,n,y對應(yīng)的x?,m)。m,n與方向的?對應(yīng)關(guān)系://m,n//1,0 從上到下//0,1 從左到右//1,1 左上到右下?//1,-1 右上到左下?還有cou?nt的值,活2、3、4還有5都?直接返回值?,死的返回c?ount+4 //返回8死4:deadf?our //返回7死3:deadt?hree //返回6死2:deadt?wo //返回5成5:five //返回4活4:alive?four //返回3活3:alive?three? //返回2活2:alive?two //返回0,完成搜索函?數(shù)sear?ch后,在iswi?n函數(shù)中調(diào)?用,如果sea?rch返回?的是5,贏了:BOOLCMyDl?g::iswin?(inti,intj){ if(searc?h(i,j,0,1)==5||searc?h(i,j,1,0)==5 ||searc?h(i,j,1,1)==5||searc?h(i,j,1,-1)==5) retur?nTRUE; retur?nFALSE?;}判斷勝負(fù)功?能完成五、人工智能/////////////////////////////AIpla?y函數(shù)//////////////////////////////////////添加成員函?數(shù)AIpl?ay,電腦下棋函?數(shù)每次人下完?后,電腦就下。所以把AI?play放?進(jìn)OnLB?utton?Up函數(shù)的?if(0==chess?[i][j])下面:if(0==chess?[i][j]) { Draw(x,y,IDB_B?LACK,pDC); chess?[i][j]=1; AIpla?y(); }此時的AI?play函?數(shù)還是個空?函數(shù)。電腦下棋應(yīng)?該找到最有?利的位置,不僅要找電?腦有利的位?置,還要找人有?利的位置,然后比較誰?更有利。如果電腦有?利,電腦進(jìn)攻;如果人有利?,電腦防守。為了尋找這?個有利位置?,添加成員函?數(shù)sear?chval?ue。searc?hvalu?e(int&best_?i,int&best_?j,intcolor?)best_?i,best_?j是最有利?的位置,注意這里用?的是&best_?i,&best_?j,即“引用參數(shù)”,引用參數(shù)可?以在函數(shù)中?改變參數(shù)數(shù)?據(jù),普通參數(shù)不?行。color?是棋子的顏?色,1為黑,-1為白。在AIpl?ay函數(shù)中?調(diào)用sea?rchva?lue函數(shù)?:voidCMyDl?g::AIpla?y(){ //白棋和黑棋?的分?jǐn)?shù) intwhite?_valu?e,black?_valu?e; //白棋和黑棋?的有利位置? intwi,wj,bi,bj; //得到分?jǐn)?shù)和?有利位置 white?_valu?e=searc?hvalu?e(wi,wj,-1); black?_valu?e=searc?hvalu?e(bi,bj,1); //準(zhǔn)備畫棋 CDC*pDC=GetDC?(); intx,y; //如果黑棋更?有利,電腦防守 if(white?_valu?e<black?_valu?e) { x=bj*34;y=bi*34; Draw(x,y,IDB_W?HITE,pDC); chess?[bi][bj]=-1; if(iswin?(bi,bj)) { Messa?geBox?("電腦勝利,結(jié)束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } } //如果白棋更?有利,電腦進(jìn)攻 else { x=wj*34;y=wi*34; Draw(x,y,IDB_W?HITE,pDC); chess?[wi][wj]=-1; if(iswin?(wi,wj)) { Messa?geBox?("電腦勝利,結(jié)束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } }}為了測試,我們先為這?個rese?archv?alue函?數(shù)設(shè)置一些?值:intCMyDl?g::searc?hvalu?e(int&best_?i,int&best_?j,intcolor?){ //白棋,有利位置設(shè)?為(1,1),返回值設(shè)為?0。 if(-1==color?) { best_?i=1;best_?j=1; retur?n0; } //黑棋,有利位置設(shè)?為(2,2),返回值設(shè)為?0. if(1==color?) { best_?i=2;best_?j=2; retur?n1; }}因?yàn)楹谄宓?分?jǐn)?shù)高,所以白棋防?守,應(yīng)該下到(2,2)位置。/////////////////////////////getsc?ore函數(shù)?/////////////////////////////////////為了得到黑?棋和白棋的?分?jǐn)?shù),添加成員函?數(shù)gets?core:這個函數(shù)的?代碼非常多?,我分開講。首先是聲明?變量,這個是根據(jù)?實(shí)際情況變?的://狀態(tài) //返回8死4:deadf?our //返回7死3:deadt?hree //返回6死2:deadt?wo //返回5成5:five //返回4活4:alive?four //返回3活3:alive?three? //返回2活2:alive?two //返回0, intdeadf?our=0,deadt?hree=0,deadt?wo=0; intfive=0,alive?four=0,alive?three?=0,alive?two=0; intstatu?s[4],score?;然后,在這個位置?下個棋,用sear?ch函數(shù)判?斷這個棋子?各個方向的?狀態(tài)。判斷結(jié)束后?記得把ch?ess[i][j]變回0。chess?[i][j]=color?; //從左到右 statu?s[0]=searc?h(i,j,0,1); //從上到下 statu?s[1]=searc?h(i,j,1,0); //從左上到右?下 statu?s[2]=searc?h(i,j,1,1); //從左下到右?上 statu?s[3]=searc?h(i,j,1,-1); chess?[i][j]=0統(tǒng)計(jì)各種情?況的數(shù)目(活2、3、4,死2、3、4,成5) for(intn=0;n<4;n++) { switc?h(statu?s[n]) { case8: deadf?our++;break?; case7: deadt?hree++;break?; case6: deadt?wo++;break?; case5: five=1;break?; case4: alive?four=1;break?; case3: alive?three?++;break?; case2: alive?two++;break?; } }給這個位置?打分,并在最后記?得返回分?jǐn)?shù)?score?。//成5 if(five)score?=10000?0; //活4 elseif(alive?four)score?=10000?; //雙死4 elseif(deadf?our>=2)score?=10000?; //死4活3 elseif(deadf?our&&alive?three?) score?=10000?; //雙活3 elseif(alive?three?>=2)score?=5000; //活3雙活2? elseif(alive?three?&&alive?two>=2) score?=5000; //活3死3 elseif(alive?three?&&deadt?hree) score?=1000; //單死4 elseif(1==deadf?our)score?=500; //單活3 elseif(1==alive?three?)score?=200; //雙活2 elseif(alive?two>=2)score?=100; //雙死3 elseif(deadt?hree>=2)score?=50; //單活2 elseif(1==alive?two)score?=10; //單死3 elseif(1==deadt?hree)score?=5; retur?nscore?;getsc?ore函數(shù)?完成/////////////////////////////searc?hvalu?e函數(shù)//////////////////////////////////然后修改s?earch?value?函數(shù):intCMy1D?lg::searc?hvalu?e(int&best_?i,int&best_?j,intcolor?){ intmaxva?lue=0,value?; for(inti=1;i<14;i++) for(intj=1;j<14;j++) { if(color?==chess?[i][j]) { for(intm=i-1;m<=i+1;m++) for(intn=j-1;n<=j+1;n++) { if(0==chess?[m][n]) { value?=getsc?ore(m,n,color?); if(maxva?lue<value?) { maxva?lue=value?; best_?i=m; best_?j=n; } } }//結(jié)束for? } }//結(jié)束for? retur?nmaxva?lue;}現(xiàn)在解釋一?下這最后完?成的函數(shù)。假設(shè)搜索黑?棋最佳位置?,整個棋盤從?左往右從上?到下掃描,當(dāng)遇到黑棋?時,分析黑棋周?圍8個位置?是否為空,如果是空則?判斷這個空?位的分?jǐn)?shù)。找到分?jǐn)?shù)最?高的位置,并返回這個?分?jǐn)?shù)。五子棋人機(jī)?對戰(zhàn)完成六、附加功能存檔、讀檔功能我們可以把?對話框上的?兩個按鈕改?造成存檔按?鈕和讀檔按?鈕,注意修改I?D。在OnIn?itDia?log函數(shù)?中,重新調(diào)整對?話框大小,和按鈕位置?//TODO:Addextra?initi?aliza?tionhere MoveW?indow?(0,0,520,560);//窗口定位 Cente?rWind?ow(); //居中窗口 GetDl?gItem?(IDC_S?AVE)->MoveW?indow?(10,500,50,20); GetDl?gItem?(IDC_O?PEN)->MoveW?indow?(70,500,50,20);查看->建立類向?qū)?給兩個按鈕?添加關(guān)聯(lián)函?數(shù)/////////////////////////////OnSav?e函數(shù)//////////////////////////////////存檔函數(shù):voidCMyDl?g::OnSav?e(){ //TODO:Addyourcontr?olnotif?icati?onhandl?ercodehere //設(shè)置保存的?文件,后綴名為.wzq CFile?Dialo?gdlg(FALSE?,"wzq", NULL,OFN_H?IDERE?ADONL?Y|OFN_O?VERWR?ITEPR?OMPT, "(*.WZQ)|*.wzq|AllFiles?|*.*||",this); //如果公共類?對話框?yàn)榇_?定 if(IDOK==dlg.DoMod?al()) dlg.GetFi?leNam?e(); //否則退出 elseretur?n; //字符串變量? CStri?ngstr; CStdi?oFile?file; //如果有問題?,退出 if(file.Open(dlg.GetFi?leNam?e(), CFile?::modeC?reate?|CFile?::modeW?rite|CFile?::typeT?ext)==0) { AfxMe?ssage?Box("saveerror?!"); retur?n; } //把數(shù)組值寫?進(jìn)文件 for(inti=0;i<15;i++){ for(intj=0;j<15;j++){ if(-1==chess?[i][j]) file.Write?Strin?g("-1"); if(0==chess?[i][j]) file.Write?Strin?g("00"); if(1==

溫馨提示

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

評論

0/150

提交評論