




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
五子棋人機?對戰(zhàn),AI很低,做參考用,僅僅為大家?提供一下思?路。開發(fā)環(huán)境:Visua?lC++6.0游戲界面:C語言游戲?2-五子棋(人機對戰(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四、判斷勝負 PAGER?EF_Toc3?39626?686\h10HYPER?LINK五、人工智能 PAGER?EF_Toc3?39626?687\h13HYPER?LINK六、附加功能 PAGER?EF_Toc3?39626?688\h17一、開始工作新建工程,選MFCAppWi?zard(exe),添上工程名?,確定。選基于對話?框,完成,確定。插入位圖網上的源碼?一般都是將?棋盤和棋子?用畫圖程序?畫出來,但我不會弄?。我的方法是?直接貼圖。先插入位圖?(BMP格式?),以下是我用?的位圖,當然你也可?以用自己的?位圖:插入位圖流?程:有時會彈出?下面這個窗?口,這是完全沒?有問題的:位圖插入后?會自動賦予?ID值,我們可以修?改一下:二、畫圖///////////////////////////Draw函數/////////////////////////////////////////添加成員函?數Draw?:Draw(intx,inty,UINTbitma?p,CDC*pDC)解釋一下:x,y是畫圖的?坐標bitma?p是圖片I?D,比如我的黑?棋圖片ID?就是IDB?_BLAC?KpDC是顯?示圖片窗口?的句柄我的畫圖函?數是下面這?樣的,其中要注意?兩個函數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 //保存畫刷、恢復畫刷為?規(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);//恢復畫刷}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所指的設?備,貼圖坐標x?,y。最后一個參?數為粘貼方?式,我們是直接?粘貼,所以是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所指的設?備,貼圖坐標x?,y,貼圖大小為?w,h,如果圖片大?小不符則拉?伸或壓縮圖?片。最后一項是?背景色,可以將圖片?背景透明化?。使用Tra?nspar?entBl?t必須包含?頭文件和類?庫,否則編譯錯?誤:#inclu?de<wingd?i.h>#pragm?acomme?nt(lib,"msimg?32.lib")函數弄好后?就調用這個?函數畫圖了?。先在OnI?nitDi?alog函?數中加入以?下代碼,調整對話框?大小,并隱藏按鈕?: //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);或者直接在?資源窗口中?調整對話框?:然后在On?Paint?函數中加入?以下代碼畫?圖: CDC*pDC=GetDC?();//獲取當前窗?口句柄 Draw(13,13,IDB_B?OARD,pDC);//畫棋盤 //Draw(0,0,IDB_B?LACK,pDC);//畫黑棋,只是為了查?看顯示效果?調整一下界?面,希望你沒有?強迫癥,可不要在調?整上花太多?時間了。下面是我做?出的效果:三、下棋現在要將棋?子準確下到?各個點上,我用的棋盤?,間距為34?,點擊鼠標時?獲取點擊坐?標x,y,然后x/34,y/34,確定棋子下?到了哪個點?上。////////////////////////OnLBu?ttonU?p函數///////////////////////////////////添加消息處?理函數:我用的消息?是WM_L?BUTTO?NUP,也就是當鼠?標左鍵抬起?來的時候,函數響應:以下是函數?代碼: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?();//獲取當前設?備句柄 Draw(x,y,IDB_B?LACK,pDC); } CDial?og::OnLBu?ttonU?p(nFlag?s,point?);}函數中,point?.x,point?.y為點擊鼠?標時的坐標?現在可以將?棋子準確地?下到點上了?,可是就算點?上有已經有?棋子了,點鼠標后也?會下棋。所以我們用?一個二維數?組存儲棋盤?上的棋子。添加成員變?量:初始化成員?變量,在OnPa?int函數?里加入下面?代碼。畫完棋盤的?同時,初始化棋盤?。for(inti=0;i<15;i++) for(intj=0;j<15;j++) chess?[i][j]=0;修改OnL?Butto?nUp函數?中的下棋代?碼原來是直?接用Dra?w(x,y,IDB_B?LACK,pDC);畫棋,現在改成下?面的內容,當點上沒有?棋時才下棋?: if(0==chess?[i][j]) { Draw(x,y,IDB_B?LACK,pDC); chess?[i][j]=1;//下的黑棋,這一點變成?1 }下棋功能完?成了。四、判斷勝負////////////////////////////iswin?函數/////////////////////////////////////////先添加一個?BOOL類?型的成員函?數iswi?n(inti,intj),每下一個棋?子都通過這?個棋子判斷?是否贏了。是則返回T?RUE(或1),否則返回F?ALSE(或0)。默認返回F?ALSE。在OnLB?utton?Up函數中?調用isw?in。如果贏了彈?出窗口"我贏了,結束戰(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?();//獲取當前設?備句柄 if(0==chess?[i][j]) { Draw(x,y,IDB_B?LACK,pDC); chess?[i][j]=1; } //判斷輸贏 if(iswin?(i,j)) { Messa?geBox?("我贏了,結束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } } CDial?og::OnLBu?ttonU?p(nFlag?s,point?);}Messa?geBox?彈出窗口"我贏了,結束戰(zhàn)斗!"Inval?idate?(FALSE?)會放出一個?WM_PA?INT消息?,間接調用O?nPain?t函數,初始化棋盤?。/////////////////////////////searc?h函數//////////////////////////////////////那到底怎么?判斷輸贏呢??我采用的是?下面這個方?法:申明變量a?live1?,alive?2,用來判斷活?棋還是死棋?。申明變量c?ount用?來判斷連子?的個數。以橫向四子?為例,我剛下了第?三個棋子。先從第三個?棋子位置開?始,往右邊掃描?,如果下的也?是黑棋,則coun?t++。如果遇到的?不是黑棋,判斷是不是?空地。如果是空地?alive?1=1,表示右邊一?頭是活的。否則ali?ve=0。然后回到第?三子位置,往左邊掃描?。對于掃描,我這里添加?一個成員函?數sear?ch用來掃?描代碼比較長?,注意不要出?錯了,不然調試很?麻煩的。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;}函數的參數?i,j是下棋的?位置,m,n表示掃描?的方向。比如從左下?角往右上角?掃描,坐標上是x?+1,y-1,對應的n=1,m=-1(x對應的是?j,n,y對應的x?,m)。m,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,完成搜索函?數sear?ch后,在iswi?n函數中調?用,如果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?;}判斷勝負功?能完成五、人工智能/////////////////////////////AIpla?y函數//////////////////////////////////////添加成員函?數AIpl?ay,電腦下棋函?數每次人下完?后,電腦就下。所以把AI?play放?進OnLB?utton?Up函數的?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函?數還是個空?函數。電腦下棋應?該找到最有?利的位置,不僅要找電?腦有利的位?置,還要找人有?利的位置,然后比較誰?更有利。如果電腦有?利,電腦進攻;如果人有利?,電腦防守。為了尋找這?個有利位置?,添加成員函?數sear?chval?ue。searc?hvalu?e(int&best_?i,int&best_?j,intcolor?)best_?i,best_?j是最有利?的位置,注意這里用?的是&best_?i,&best_?j,即“引用參數”,引用參數可?以在函數中?改變參數數?據,普通參數不?行。color?是棋子的顏?色,1為黑,-1為白。在AIpl?ay函數中?調用sea?rchva?lue函數?:voidCMyDl?g::AIpla?y(){ //白棋和黑棋?的分數 intwhite?_valu?e,black?_valu?e; //白棋和黑棋?的有利位置? intwi,wj,bi,bj; //得到分數和?有利位置 white?_valu?e=searc?hvalu?e(wi,wj,-1); black?_valu?e=searc?hvalu?e(bi,bj,1); //準備畫棋 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?("電腦勝利,結束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } } //如果白棋更?有利,電腦進攻 else { x=wj*34;y=wi*34; Draw(x,y,IDB_W?HITE,pDC); chess?[wi][wj]=-1; if(iswin?(wi,wj)) { Messa?geBox?("電腦勝利,結束戰(zhàn)斗!","提示",MB_OK?); Inval?idate?(FALSE?); } }}為了測試,我們先為這?個rese?archv?alue函?數設置一些?值:intCMyDl?g::searc?hvalu?e(int&best_?i,int&best_?j,intcolor?){ //白棋,有利位置設?為(1,1),返回值設為?0。 if(-1==color?) { best_?i=1;best_?j=1; retur?n0; } //黑棋,有利位置設?為(2,2),返回值設為?0. if(1==color?) { best_?i=2;best_?j=2; retur?n1; }}因為黑棋的?分數高,所以白棋防?守,應該下到(2,2)位置。/////////////////////////////getsc?ore函數?/////////////////////////////////////為了得到黑?棋和白棋的?分數,添加成員函?數gets?core:這個函數的?代碼非常多?,我分開講。首先是聲明?變量,這個是根據?實際情況變?的://狀態(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函數判?斷這個棋子?各個方向的?狀態(tài)。判斷結束后?記得把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)計各種情?況的數目(活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?; } }給這個位置?打分,并在最后記?得返回分數?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函數?完成/////////////////////////////searc?hvalu?e函數//////////////////////////////////然后修改s?earch?value?函數: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; } } }//結束for? } }//結束for? retur?nmaxva?lue;}現在解釋一?下這最后完?成的函數。假設搜索黑?棋最佳位置?,整個棋盤從?左往右從上?到下掃描,當遇到黑棋?時,分析黑棋周?圍8個位置?是否為空,如果是空則?判斷這個空?位的分數。找到分數最?高的位置,并返回這個?分數。五子棋人機?對戰(zhàn)完成六、附加功能存檔、讀檔功能我們可以把?對話框上的?兩個按鈕改?造成存檔按?鈕和讀檔按?鈕,注意修改I?D。在OnIn?itDia?log函數?中,重新調整對?話框大小,和按鈕位置?//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);查看->建立類向導?給兩個按鈕?添加關聯函?數/////////////////////////////OnSav?e函數//////////////////////////////////存檔函數:voidCMyDl?g::OnSav?e(){ //TODO:Addyourcontr?olnotif?icati?onhandl?ercodehere //設置保存的?文件,后綴名為.wzq CFile?Dialo?gdlg(FALSE?,"wzq", NULL,OFN_H?IDERE?ADONL?Y|OFN_O?VERWR?ITEPR?OMPT, "(*.WZQ)|*.wzq|AllFiles?|*.*||",this); //如果公共類?對話框為確?定 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; } //把數組值寫?進文件 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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 交通運輸線路現場調研與評估合同
- 【課件】+相反數+課件+人教版數學七年級上冊+
- 公司大型崗亭管理制度
- 年產塑料制品100萬件環(huán)境影響評價報告
- 崗位作業(yè)標準管理制度
- 醫(yī)療廢物管理管理制度
- 基層公章使用管理制度
- 公開招租現場管理制度
- 公司越級匯報管理制度
- 醫(yī)院藥品入賬管理制度
- 通用綠色簡約小清新PPT模板
- 徐匯濱江規(guī)劃和出讓情況專題培訓課件
- 場區(qū)清表施工方案及工藝方法
- 標線首件施工總結
- 鋼箱梁梁格模型(彎橋)解決方案
- 環(huán)刀法壓實度自動計算程序
- 項目-桿塔1b模塊司令圖
- 危大工程驗收記錄表(模板工程)
- 天津市新版就業(yè)、勞動合同登記名冊
- 甲酸鈣生產工藝
- 法律診所完整版教學ppt課件全套教程
評論
0/150
提交評論