五子棋C++课设报告_第1页
五子棋C++课设报告_第2页
五子棋C++课设报告_第3页
五子棋C++课设报告_第4页
五子棋C++课设报告_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++面向对象课程设计一、需求分析1.1选做五子棋课题的目的现如今,我们生活在一个充满竞争的时代。上班族为了完成公司业务,每天超负荷的工作;学生为了不落后他人每天早起晚睡不断地学习,压力巨大。为了缓解压力,使自己在工作、学习之余娱乐一下,活跃大脑,提高工作、学习效率,益智类游戏越来越受人们的关注和喜爱,五子棋作为益智类游戏之一,更是倍受人们的喜爱,所以程序员对于五子棋的开发也有了很多关注。五子棋是一种两人对弈的纯策略型棋类游戏,棋具与围棋通用,是起源于中国古代的传统黑白棋种之一。现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(FiveinaRow的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。基于此文化背景以及我对五子棋的喜爱,在本次C++课程设计中我选择了五子棋游戏课题,通过此次课程设计,我希望能达到以下目的:最基本也是最重要的:顺利完成课题要求,设计出五子棋游戏。通过实践加强对C++面向对象程序设计知识的理解和掌握,能更好的理解、掌握类的应用。提高自己的综合运用能力、问题分析能力以及编程能力,养成良好的编程习惯。了解MFC,基本掌握用MFC开发程序的方法,学会用MFC开发出界面友好、实用可靠的Windows应用程序。1.2程序实现的功能经过两周的课程设计,最终较圆满的完成了课题要求,开发出了五子棋游戏程序,本五子棋游戏主要实现了以下功能:(1)有开始游戏、重新开始、退出游戏等基本功能。(2)游戏模式分为人人对战、人机对战以及电脑与电脑对战等三种模式。(3)在人机对战模式中还可以选择不同的难度等级,共分为弱智级、入门级、成熟级、专业级和大师级等五个等级,玩家可根据实际情况选择不同的难度等级进行对弈。(4)本游戏还有悔棋功能,让电脑给出下一步建议功能。(5)人机对战时默认为玩家先走,此时可以选择换方选项让电脑先走。(6)人人对战和人机对战时还可选择更改玩家姓名,让玩家输入自己的姓名。(7)本游戏还有音效功能,默认为开启音效状态,此时玩家也可选择关闭音效。本五子棋游戏目前只实现了上述功能,其他更多的功能有待在日后逐步添加。二、设计内容2.1设计要求基本要求:画出棋盘,实现人机对弈。2.2设计思路此次课程设计中,我采用的是MFC基于对话框来编写五子棋程序的。所以主对话框类RenjuFDlg就是本程序的核心类,在该类中完成了初始化界面、在对弈过程中对棋盘的重绘以及基本功能的实现等,该类调用其他类最终实现了本五子棋游戏的所有功能。由于五子棋游戏中,有相当的篇幅是算法的部分,无论是人机对弈、人人对弈还是电脑对弈都需要合理算法的支持,所以我把所有五子棋的算法封装在了FiveStoneProcess类中,该类主要完成了对弈过程中根据不同的难度等级选择不同的算法进行对弈的功能。2.3功能模块图2.4主程序及其主要模块的流程图主程序流程图人机对战模块流程图OnLButtonDown(UINTnFlags,CPointpoint)函数流程图2.5关键代码及说明以下为本程序的主要函数代码及功能说明。1.核心类RenjuDlg中的主要函数代码:(1)OnInitDialog()函数:用于初始化一些数据BOOLCRenjuDlg::OnInitDialog(){ CDialog::OnInitDialog(); //Add"About..."menuitemtosystemmenu.//IDM_ABOUTBOXmustbeinthesystemcommandrange. ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX<0xF000); CMenu*pSysMenu=GetSystemMenu(FALSE); if(pSysMenu!=NULL) { CStringstrAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if(!strAboutMenu.IsEmpty() { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu); } }//Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE); //Setbigicon SetIcon(m_hIcon,FALSE); //SetsmalliconSetDlgItemText(IDC_Player1,_T("玩家"));//初始化界面编辑框的内容SetDlgItemText(IDC_Player2,_T("一休哥")); bmp[0].LoadBitmap(IDB_GRADE1);//加载位图 bmp[1].LoadBitmap(IDB_GRADE2); bmp[2].LoadBitmap(IDB_GRADE3); bmp[3].LoadBitmap(IDB_GRADE4); bmp[4].LoadBitmap(IDB_GRADE5); bmp[5].LoadBitmap(IDB_BLACK); bmp[6].LoadBitmap(IDB_WHITE); bmp[7].LoadBitmap(IDB_BLACK2); bmp[8].LoadBitmap(IDB_WHIRE2); bmp[9].LoadBitmap(IDB_CVSC); bmp[10].LoadBitmap(IDB_Renren); CBitmapbmp; bmp.LoadBitmap(IDB_TABLE);m_brush=CreatePatternBrush((HBITMAP)bmp); bmp.DeleteObject(); thiswnd=this->GetSafeHwnd(); thisdlg=this; OnGrade3(); OnStart(); //TODO:Addextrainitializationhere returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}(2)OnPaint()函数:此函数为该类最重要的函数之一,主要用于在游戏过程中对棋盘的重绘以及对游戏界面的重绘,同时还调用其他函数来判断当前局面的输赢状况等。voidCRenjuDlg::OnPaint(){ if(IsIconic()) { CPaintDCdc(this);//devicecontextforpainting SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0); //Centericoninclientrectangle intcxIcon=GetSystemMetrics(SM_CXICON); intcyIcon=GetSystemMetrics(SM_CYICON); CRectrect; GetClientRect(&rect); intx=(rect.Width()-cxIcon+1)/2; inty=(rect.Height()-cyIcon+1)/2; //Drawtheicon dc.DrawIcon(x,y,m_hIcon); } else { CPaintDCdc(this); CDCdcmem; BITMAPbm; dcmem.CreateCompatibleDC(&dc); if(is_cvsc) {//电脑对战 dcmem.SelectObject(&bmp[9]);GetObject(bmp[9],sizeof(BITMAP),(LPVOID)&bm);//在界面相应的位置插入位图dc.BitBlt(446,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); switch(firstgrade) {//根据先手电脑的等级在第一个编辑框中输入不同的文字 case1:SetDlgItemText(IDC_Player1,_T("蜡笔小新"));break;case2:SetDlgItemText(IDC_Player1,_T("樱桃小丸子"));break;case3:SetDlgItemText(IDC_Player1,_T("一休哥"));break;case4:SetDlgItemText(IDC_Player1,_T("功夫熊猫"));break;case5:SetDlgItemText(IDC_Player1,_T("五子棋大师"));break; }switch(secondgrade) {//根据后手电脑的等级在第二个编辑框中输入不同的文字 case1:SetDlgItemText(IDC_Player2,_T("蜡笔小新"));break;case2:SetDlgItemText(IDC_Player2,_T("樱桃小丸子"));break;case3:SetDlgItemText(IDC_Player2,_T("一休哥"));break;case4:SetDlgItemText(IDC_Player2,_T("功夫熊猫"));break;case5:SetDlgItemText(IDC_Player2,_T("五子棋大师"));break; } } elseif(m_renren) {//人人对战 dcmem.SelectObject(&bmp[10]); GetObject(bmp[10],sizeof(BITMAP),(LPVOID)&bm);//在相应位置插入相应位图 dc.BitBlt(445,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); //设置两个编辑框的内容 SetDlgItemText(IDC_Player1,name1); SetDlgItemText(IDC_Player2,name2); } else { SetDlgItemText(IDC_Player1,name);//设置第一个编辑框的内容 switch(grade) {//根据当前电脑等级在对话框相应位置加载不同图片 //同时对第二个编辑框设置不同的内容 case1: dcmem.SelectObject(&bmp[0]);//IDB_GRADE1 GetObject(bmp[0],sizeof(BITMAP),(LPVOID)&bm); dc.BitBlt(445,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); SetDlgItemText(IDC_Player2,_T("蜡笔小新")); break; case2: dcmem.SelectObject(&bmp[1]);//IDB_GRADE2 GetObject(bmp[1],sizeof(BITMAP),(LPVOID)&bm); dc.BitBlt(446,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); SetDlgItemText(IDC_Player2,_T("樱桃小丸子")); break; case3: dcmem.SelectObject(&bmp[2]);//IDB_GRADE3 GetObject(bmp[2],sizeof(BITMAP),(LPVOID)&bm); dc.BitBlt(445,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); SetDlgItemText(IDC_Player2,_T("一休哥")); break; case4: dcmem.SelectObject(&bmp[3]);//IDB_GRADE4 GetObject(bmp[3],sizeof(BITMAP),(LPVOID)&bm); dc.BitBlt(430,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); SetDlgItemText(IDC_Player2,_T("功夫熊猫")); break; case5: dcmem.SelectObject(&bmp[4]);//IDB_GRADE5 GetObject(bmp[4],sizeof(BITMAP),(LPVOID)&bm); dc.BitBlt(446,60,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); SetDlgItemText(IDC_Player2,_T("五子棋大师")); break; } } for(inti=1;i<=15;i++)//每下一颗棋子,都要重绘一次棋盘上的棋子 for(intj=1;j<=15;j++) {inttempx,tempy;//用于记录当前棋子该放的坐标 switch(points[i][j]) { case1://黑色棋 GetObject(bmp[5],sizeof(BITMAP),(LPVOID)&bm); tempx=24*i-bm.bmWidth/2-5; tempy=24*j-bm.bmHeight/2-5; dcmem.SelectObject(&bmp[5]);dc.BitBlt(tempx+10,tempy+10,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); break; case2://白色棋 GetObject(bmp[6],sizeof(BITMAP),(LPVOID)&bm);//"white" tempx=24*i-bm.bmWidth/2-5; tempy=24*j-bm.bmHeight/2-5; dcmem.SelectObject(&bmp[6]);dc.BitBlt(tempx+10,tempy+10,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); break; case3://black2,表示机器刚走的黑子 GetObject(bmp[7],sizeof(BITMAP),(LPVOID)&bm);//"gray1" tempx=24*i-bm.bmWidth/2-5; tempy=24*j-bm.bmHeight/2-5; dcmem.SelectObject(&bmp[7]); dc.BitBlt(tempx+10,tempy+10,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); points[i][j]=1;//变回正常色 break; case4://white2,表示机器刚走的白子 GetObject(bmp[8],sizeof(BITMAP),(LPVOID)&bm);//"gray2" tempx=24*i-bm.bmWidth/2-5; tempy=24*j-bm.bmHeight/2-5; dcmem.SelectObject(&bmp[8]); dc.BitBlt(tempx+10,tempy+10,bm.bmWidth,bm.bmHeight,&dcmem,0,0,SRCCOPY); points[i][j]=2;//变回正常色 break; default:break; } } if(!stop) { if(fivestone.has_tie())//平局 { SetWindowText("动漫五子棋"); if(soundeffect)//开启音效,则播放相应的音乐 sndPlaySound("IDR_WIN",SND_RESOURCE|SND_ASYNC); stop=true; if(!m_renren&&!is_cvsc)//人机对战 MyMessageBox("累死我了,终于平了!"); elseif(m_renren)//人人对照 MyMessageBox("看来真是棋逢对手,你们平了!"); else {//电脑对战 OnCvsc(); MyMessageBox("电脑黑棋和电脑白棋战平!"); } } if(fivestone.has_five(1))//黑棋连成五子,黑棋胜利 {SetWindowText("动漫五子棋"); stop=true;//标志一局结束 if(first) {//只有人机对战时,first才可能为真,此时表示计算机执黑子先下,则计算机胜利 if(soundeffect) sndPlaySound("IDR_LOST",SND_RESOURCE|SND_ASYNC); MyMessageBox("你输了,不过别灰心,失败乃成功之母哦!"); } else {SetWindowText("动漫五子棋"); if(soundeffect) sndPlaySound("IDR_WIN",SND_RESOURCE|SND_ASYNC); if(!m_renren&&!is_cvsc)//人机对战 MyMessageBox("太厉害了,你赢了,再接再厉!"); elseif(is_cvsc)//电脑对战 { OnCvsc(); MyMessageBox("电脑黑棋战胜了电脑白棋!"); } else//人人对战 MyMessageBox("黑棋很厉害哦,你赢了~白棋也不要灰心,继续努力!o(≧v≦)o"); } } if(fivestone.has_five(2))//白棋连成五子,白棋胜利 { stop=true; if(first)//人机对战,且电脑执黑子先下,则人胜利 { if(soundeffect) sndPlaySound("IDR_WIN",SND_RESOURCE|SND_ASYNC); MyMessageBox("太厉害了,你赢了,再接再厉!"); } else { if(!m_renren&&!is_cvsc)//人机对战,电脑胜利 {if(soundeffect) sndPlaySound("IDR_LOST",SND_RESOURCE|SND_ASYNC); MyMessageBox("你输了,不过别灰心,失败乃成功之母哦!"); } else {if(soundeffect)sndPlaySound("IDR_WIN",SND_RESOURCE|SND_ASYNC); if(m_renren&&!is_cvsc)//人人对战 MyMessageBox("白棋很厉害哦,你赢了~黑棋也不要灰心,继续努力!o(≧v≦)o"); else {//电脑对战 OnCvsc(); MyMessageBox("电脑白棋战胜了电脑黑棋!"); } } } } if(stop||is_cvsc)//一局结束,则不能悔棋,也不能使用下一步建议 {//悔棋选项变灰this->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_GRAYED);//下一步建议选项变灰this->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_GRAYED); } else {this->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_ENABLED);this->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_ENABLED);}}CDialog::OnPaint();}}(3)OnStart()函数:主要用于在重新开始一局时清空上一局的所有数据。voidCRenjuDlg::OnStart()//重新开始一局{ //TODO:Addyourcommandhandlercodehere if(soundeffect)//开启音效时,则播放音乐 sndPlaySound("IDR_NEWGAME",SND_RESOURCE|SND_ASYNC); fivestone.clear(); for(inti=1;i<=15;i++)//清空对棋盘上的棋子的记录 for(intj=1;j<=15;j++) points[i][j]=0; stepcount=0;//走的总棋数清零 stop=false; if(first&&!m_renren&&!is_cvsc) {//如果是人机对战且计算机先走,则开局时计算机先走一子 fivestone.points[8][8]=1;//计算机先走时,默认走天元(棋盘正中间) //计算机先走 points[8][8]=3; steps[stepcount].x=8; steps[stepcount].y=8; stepcount++; } if(m_renren)//人人对战 SetWindowText("动漫五子棋--现在该黑棋走棋!"); InvalidateRect(CRect(10,10,400,400)); //重绘棋盘}(4)OnCvsc()函数:主要用于处理电脑对战时的情况。voidCRenjuDlg::OnCvsc(){ //TODO:Addyourcommandhandlercodehere if(!is_cvsc) { CVCDlgcdlg; if(cdlg.DoModal()==IDOK) {//电脑对战 is_cvsc=!is_cvsc; //改变菜单栏的内容this->GetMenu()->ModifyMenu(IDM_CVSC,MF_BYCOMMAND,IDM_CVSC,"停止电脑对战"); OnStart();//调用OnStart()初始化游戏 fivestone.points[8][8]=1;//默认先走黑棋且第一步走天元位置 points[8][8]=3; steps[stepcount].x=8; steps[stepcount].y=8; stepcount++; stop=false; InvalidateRect(CRect(406,49,600,240));//开始电脑对战时的线程函数 CWinThread*cwt=AfxBeginThread(&cvsc,NULL); cvscThread=cwt->m_hThread; SetWindowText("动漫五子棋——电脑与电脑对战"); //改变菜单栏的相应菜单项状态 this->GetMenu()->EnableMenuItem(IDM_RENREN,MF_BYCOMMAND|MF_GRAYED); this->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_GRAYED); this->GetMenu()->EnableMenuItem(IDM_START,MF_BYCOMMAND|MF_GRAYED); this->GetMenu()->EnableMenuItem(IDM_CHANGE,MF_BYCOMMAND|MF_GRAYED; this->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_GRAYED); } } else {//停止电脑对战 is_cvsc=false; if(cvscThread!=NULL) {//结束电脑对战的线程函数 TerminateThread(cvscThread,0); cvscThread=NULL; } //改变菜单栏的相应内容 SetWindowText("动漫五子棋"); this->GetMenu()->ModifyMenu(IDM_CVSC,MF_BYCOMMAND,IDM_CVSC,"电脑与电脑对战"); fivestone.setGrade(grade); InvalidateRect(CRect(406,49,600,240)); this->GetMenu()->EnableMenuItem(IDM_RENREN,MF_BYCOMMAND|MF_ENABLE; this->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_ENABLED; this->GetMenu()->EnableMenuItem(IDM_START,MF_BYCOMMAND|MF_ENABLED); if(!m_renren) this->GetMenu()->EnableMenuItem(IDM_CHANGE,MF_BYCOMMAND|MF_ENABLED); this->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_ENABLED; } }(5)computerprocess(LPVOIDpParam)函数:该函数为线程函数,用于处理人机对战时,电脑下子的线程。voidCRenjuDlg::MyMessageBox(CStrings){ ::MessageBox(thiswnd,s,"动漫五子棋",MB_OK); }UINTcomputerprocess(LPVOIDpParam)//处理人机对战时,电脑下子的线程{//改变相应菜单项的状态thisdlg->GetMenu()->EnableMenuItem(IDM_RENREN,MF_BYCOMMAND|MF_GRAYED);thisdlg->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_GRAYED);thisdlg->GetMenu()->EnableMenuItem(IDM_START,MF_BYCOMMAND|MF_GRAYED);thisdlg->GetMenu()->EnableMenuItem(IDM_CHANGE,MF_BYCOMMAND|MF_GRAYED);thisdlg->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_GRAYED);thisdlg->GetMenu()->EnableMenuItem(IDM_CVSC,MF_BYCOMMAND|MF_GRAYED); intx,y;//计算机走的子 if(first)//计算机执黑子先走 fivestone.getpoint(x,y,1);//得到该走的坐标位置,1代表黑子 elsefivestone.getpoint(x,y,2);//得到该走的坐标位置,2代表白子 if(x!=0) { //当前还可下棋子 if(soundeffect) sndPlaySound("IDB_PUT",SND_RESOURCE|SND_ASYNC);//播放音效 if(first) { 电脑先走 fivestone.points[x][y]=1;//记录棋子颜色为黑 points[x][y]=3;//用不同颜色表示电脑刚下的棋子 } else { fivestone.points[x][y]=2; points[x][y]=4;//用不同颜色表示电脑刚下的棋子 } steps[stepcount].x=x;//记录位置 steps[stepcount].y=y; stepcount++; //总步数加1 InvalidateRect(thiswnd,getpointRect(x,y),FALSE);//绘棋子 stop=false; if(stepcount>2)//下的总步数大于2 //去掉电脑在上一步所下棋子的标记 InvalidateRect(thiswnd,getpointRect(steps[stepcount-3].x,steps[stepcount-3].y),FALSE); //改变相应菜单项的状态thisdlg->GetMenu()->EnableMenuItem(IDM_RENREN,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_START,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_CHANGE,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_CVSC,MF_BYCOMMAND|MF_ENABLED);} else{ //已经有一方连成五子(实际上只有人赢的时候才会到这里)thisdlg->GetMenu()->EnableMenuItem(IDM_RENREN,MF_BYCOMMAND|MF_ENABLED)thisdlg->GetMenu()->EnableMenuItem(IDM_REGRET,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_START,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_CHANGE,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_ADVICE,MF_BYCOMMAND|MF_ENABLED);thisdlg->GetMenu()->EnableMenuItem(IDM_CVSC,MF_BYCOMMAND|MF_ENABLED); stop=false; InvalidateRect(thiswnd,getpointRect(x,y),FALSE);//绘棋子 } return1;}(6)OnLButtonDown()函数:用于在游戏过程中对单击鼠标左键事件的响应。voidCRenjuDlg::OnLButtonDown(UINTnFlags,CPointpoint){ //TODO:Addyourmessagehandlercodehereand/orcalldefault //左键下黑子 if(stop)return;//一局已结束,则不做任何相应 if(is_cvsc)return;//电脑对战,则不对人单击鼠标事件做出相应 //把物理坐标转换为棋盘坐标 intn1=round((double)(point.x)/24.0); intn2=round((double)(point.y)/24.0); if(n1<=0||n2<=0||n1>15||n2>15) {//点击位置不正确 MyMessageBox("不正确的下子位置!"); return; } if(fivestone.points[n1][n2]==0) //点击位置没有棋子子 { if(soundeffect) sndPlaySound("IDR_PUT",SND_RESOURCE|SND_ASYNC); if(!m_renren) {//人机对战情况 if(first) {//计算机先走,则人用白子 fivestone.points[n1][n2]=2; points[n1][n2]=2; } else {//人先走,则人用黑子 fivestone.points[n1][n2]=1; points[n1][n2]=1; } stop=true; steps[stepcount].x=n1;//记录位置 steps[stepcount].y=n2; stepcount++; if(!fivestone.has_tie()) {//棋盘未下满,开始人机对战时电脑线程函数 AfxBeginThread(&computerprocess,NULL); } else stop=false; InvalidateRect(getpointRect(n1,n2),FALSE);//将刚才人下的棋子位置重绘//将刚才电脑下的棋子位置重绘 InvalidateRect(getpointRect(steps[stepcount-2].x,steps[stepcount-2].y),FALSE); } else { //是人人对战 if(stepcount%2==0)//当前下的是黑棋 { fivestone.points[n1][n2]=1; points[n1][n2]=1; SetWindowText("动漫五子棋--现在该白棋走!"); } else {//当前下的是白棋 fivestone.points[n1][n2]=2; points[n1][n2]=2; SetWindowText("动漫五子棋--现在该黑棋走!"); } steps[stepcount].x=n1; steps[stepcount].y=n2; stepcount++; InvalidateRect(getpointRect(n1,n2),FALSE);//绘制棋子 } } CDialog::OnLButtonDown(nFlags,point);}(7)OnRegret()函数:用于在游戏过程中的悔棋。voidCRenjuDlg::OnRegret(){ //TODO:Addyourcommandhandlercodehere //悔棋 if(!m_renren) {//人机对战 if(stepcount>=2) {//人机对战时一次要悔两步棋,一步是电脑下的,一步是人下的。 fivestone.points[steps[stepcount-1].x][steps[stepcount-1].y]=0; fivestone.points[steps[stepcount-2].x][steps[stepcount-2].y]=0; points[steps[stepcount-1].x][steps[stepcount-1].y]=0; points[steps[stepcount-2].x][steps[stepcount-2].y]=0; //重新绘制棋盘相应位置 InvalidateRect(getpointRect(steps[stepcount-1].x,steps[stepcount-1].y)); InvalidateRect(getpointRect(steps[stepcount-2].x,steps[stepcount-2].y)); stepcount=stepcount-2; } } else { //在人人对战模式下,一次只要悔一步棋 if(stepcount>=1) { fivestone.points[steps[stepcount-1].x][steps[stepcount-1].y]=0; points[steps[stepcount-1].x][steps[stepcount-1].y]=0; //重新绘制棋盘相应位置 InvalidateRect(getpointRect(steps[stepcount-1].x,steps[stepcount-1].y)); stepcount=stepcount-1; if(stepcount%2==0) SetWindowText("动漫五子棋--现在该黑棋走棋!"); elseSetWindowText("动漫五子棋--现在该白棋走棋!"); } }}2.FiveStoneProcess类中的核心代码五子棋游戏中有很大一部分是算法,不论哪种游戏模式都需要合理算法的支持,由于我所设计的五子棋游戏分为五个难度等级,所以算法部分更是巨大。首先介绍一下在所有算法中用到的搜索方向。不论是判断胜负还是查看一个子的周围情况,对于一个棋子来说,要从四个方向搜索,分别为横向、纵向、斜右下和斜左下,每个方向正负搜索两次。图2.1搜索方向其次,介绍一下主要算法。五子棋的算法主要包括:估值函数、搜索算法和判断胜负等。其中判断胜负就是从上一段所说的四个方向进行遍历,最终得到结果。不同的棋型,优先级不同。估值时,也要从以上四个方向考虑,由估值函数得到分值最高的点为电脑下棋的点,本五子棋游戏的估值函数参照了网上的一些方法,由于篇幅有限,在这里就不详细介绍估值方法了。在博弈问题中,每一个格局可供选择的行动方案都有很多,因此会生成十分庞大的博弈树。一般地只生成一定深度的博弈树,然后进行极小极大搜索。我们不用把每个节点都搜索一遍也可获得和极大极小搜索同样结果的走步,不搜索分支节点而舍弃该分支的过程叫剪枝。五子棋算法中就用到了Alpha–Beta剪枝算法,具体的专业知识就不在这里详细介绍了,网上有很多相关算法的介绍,感兴趣的话可以从网上查阅。对于不同的难度等级,搜索的深度也不同,难度等级越大,搜索的深度越深,电脑考虑的时间也就越长。由于本五子棋游戏的算法很庞大,所以只选取了其中的部分关键代码,下面是一些主要函数和说明。getpoint1()函数:难度等级为1(弱智级)的算法。voidFiveStoneProcess::getpoint1(int&x,int&y,intcolor){ //一共有6个算法 POINTtempresult[225]; intcount=0; intanticolor;//对方的color if(color==1)anticolor=2; elseanticolor=1; x=0;y=0; if(has_five(1)||has_five(2)){ return;//已经连成5子,什么都不做了 } if(can_five(color,x,y)) return; if(can_five(anticolor,x,y)) return;//看对方能否连成5子 if(has_alive(color,count,tempresult)) { //存在活子,直接输出活子(应从结果集中random选取) inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } if(has_alive(anticolor,count,tempresult)) { //看对方是否存在活子 inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } getclose_small(count,tempresult); inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y;}(2)getpoint2():难度等级为2(入门级)的算法。voidFiveStoneProcess::getpoint2(int&x,int&y,intcolor){ //一共有10个算法, //在grade3的基础上,再减少一些功能,比如,将qianmodel算法全部去掉 //采用随机算法 POINTtempresult[225]; intcount=0; intanticolor;//对方的color if(color==1)anticolor=2; elseanticolor=1; x=0;y=0; if(has_five(1)||has_five(2))return; intcur_time=GetCurrentTime(); if(can_five(color,x,y)) { return;//如果能连成5子,那么返回 } if(can_five(anticolor,x,y)) { return;//看对方能否连成5子 } if(has_alive(color,count,tempresult)) { //存在活子,直接输出活子(应从结果集中random选取) inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } if(has_twolevel_four(color,count,tempresult)) { //存在一个存在四子的二阶活子 inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } if(has_alive(anticolor,count,tempresult)) { //看对方是否存在活子 inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; }if(has_twolevel_four(anticolor,count,tempresult)){ //存在一个存在四子的二阶活子 inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return;} if(has_twolevel_pure(color,count,tempresult)) { //存在二阶活子,直接输出二阶活子(应从结果集中random选取) inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } if(has_twolevel(anticolor,count,tempresult)) { //看对方是否存在二阶活子 inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y; return; } getclose_small(count,tempresult); inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y;}(3)getpoint3():难度等级为3(成熟级)的算法。voidFiveStoneProcess::getpoint3(int&x,int&y,intcolor){ //一共有12个算法, //只能辨别纯牵制子匹配,即如果你有掺杂牵制子匹配,那么就可胜利 POINTtempresult[225]; intcount=0; intanticolor;//对方棋子的颜色 if(color==1)anticolor=2; elseanticolor=1; x=0;y=0; if(has_five(1)||has_five(2)) { return;//已经连成5子,什么都不做了 } if(can_five(color,x,y)) { return;//如果能连成5子,那么返回 } if(can_five(anticolor,x,y)) { return;//看对方能否连成5子 } if(has_alive(color,count,tempresult)) { //存在活子,直接输出活子(应从结果集中random选取) selectqianmodel3(color,x,y,tempresult,count); return; } if(has_twolevel_four(color,count,tempresult)) { //存在一个存在四子的二阶活子 selectqianmodel3(color,x,y,tempresult,count); return; } if(has_alive(anticolor,count,tempresult)) { //看对方是否存在活子 selectqianmodel3(color,x,y,tempresult,count); return; } if(has_twolevel_four(anticolor,count,tempresult)) { //存在一个存在四子的二阶活子 selectqianmodel3(color,x,y,tempresult,count); return; } //不存在一阶活子,考察是否存在二阶活子 if(has_twolevel_pure(color,count,tempresult)) { //存在二阶活子,直接输出二阶活子(应从结果集中random选取) selectqianmodel3(color,x,y,tempresult,count); return; } if(has_qianmodel(color,count,tempresult)) {//考察是否形成了牵制子 selectqianmodel3(color,x,y,tempresult,count); return; } if(has_twolevel(anticolor,count,tempresult)) { //看对方是否存在二阶活子 selectqianmodel3(color,x,y,tempresult,count); return; } if(has_qianmodel(anticolor,count,tempresult)) {//考察对方是否形成了牵制子 selectqianmodel3(color,x,y,tempresult,count); return; } getmax(count,tempresult); inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y;}(4)getpoint4():难度等级为4(专业级)的算法。voidFiveStoneProcess::getpoint4(int&x,int&y,intcolor){ //一共有26个算法, POINTtempresult[225]; intcount=0; intanticolor;//对方的color if(color==1)anticolor=2; elseanticolor=1; x=0;y=0; if(has_five(1)||has_five(2)) { return;//已经连成5子,什么都不做了 } if(can_five(color,x,y)) { return;//如果能连成5子,那么返回 } if(can_five(anticolor,x,y)) { return;//看对方能否连成5子 } if(has_alive(color,count,tempresult)) { //存在活子,直接输出活子(应从结果集中random选取) selectqianmodel(color,x,y,tempresult,count); return; } if(has_twolevel_four(color,count,tempresult)) { //存在一个存在四子的二阶活子 selectqianmodel(color,x,y,tempresult,count); return; } if(has_alive_defent(anticolor,count,tempresult)) { //看对方是否存在活子 selectqianmodel(color,x,y,tempresult,count); return; } if(!defent_success&&has_canfour(color,count,tempresult)) { //不能防住对方的一阶活子,冲四 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_alive_defent_low(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_alive(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(has_twolevel_four_defent(anticolor,count,tempresult)) { //存在一个存在四子的二阶活子 selectqianmodel(color,x,y,tempresult,count); return; } if(!defent_success&&has_canfour(color,count,tempresult)) { //不能防住对方的强二阶活子,冲四 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_twolevel_four_defent_low(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_twolevel_four(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(has_twolevel_pure(color,count,tempresult)) { //存在二阶活子,直接输出二阶活子(应从结果集中random选取) selectqianmodel(color,x,y,tempresult,count); return; } if(has_qianmodel_addone(color,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(has_qianmodel(color,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(has_twolevel_qianmodel(color,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(has_twolevel_defent(anticolor,count,tempresult)) { //看对方是否存在二阶活子 selectqianmodel(color,x,y,tempresult,count); return; } if(!defent_success&&has_canfour(color,count,tempresult)) { //不能防住对方的二阶活子,冲四 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_twolevel_defent_low(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(!defent_success&&has_twolevel(anticolor,count,tempresult)) { //还是不能防住,那么只挡某一个活子即可 selectqianmodel(color,x,y,tempresult,count); isdanger=true; return; } if(has_qianmodel_addone(anticolor,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(has_qianmodel(anticolor,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(has_twolevel_qianmodel(anticolor,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } if(make_qianmodel(color,count,tempresult)) { selectqianmodel(color,x,y,tempresult,count); return; } getmax(count,tempresult); inttempi=random(0,count-1); x=tempresult[tempi].x; y=tempresult[tempi].y;}(5)getpoint5():难度等级为5(大师级)的算法。voidFiveStoneProcess::getpoint5(int&x,int&y,intcolor){ //一共有53个算法, //最高等级 /*算法过程如下计算机找到一阶活子计算机找到强二阶活子计算机两个牵制子和一个已下子强匹配!计算机三个牵制子强匹配计算机二阶牵制子强匹配计算机三阶牵制子强匹配//**计算机强打击子找到人的一阶活子d找到人的强二阶活子d人两个牵制子和一个已下子强匹配d人三个牵制子强匹配d人二阶牵制子强匹配d//人三阶牵制子强匹配d计算机找到二阶活子计算机两个牵制子和一个已下子匹配计算机三个牵制子匹配计算机二阶牵制子计算机三阶牵制子**计算机打击子//**计算机二阶打击子>50不采用找到人的二阶活子d计算机冲三(color=2时,<20不采用)计算机冲四(color=2时,<20不采用)人两个牵制子和一个已下子匹配d人三个牵制子匹配d人二阶牵制子d//人三阶牵制子>50时不采用//**人强打击子>50时不采用//**计算机打击子_low//**计算机二阶打击子_low>50不采用**人打击子>50时不采用//**人二阶打击子>50时不采用//计算机制造打击子//计算机制造二阶牵制子匹配//计算机制造三阶牵制子匹配//计算机制造二阶活子//计算机冲二子和制造牵制子匹配(color=2时,<10不采用)计算机冲二子(color=2时,<10不采用)计算机制造牵制子匹配(color=2时,<10不采用)赋值算法 */ POINTtempresult[225]; intcount=0; intanticolor;//对方的color if(color==1)anticolor=2; elseanticolor=1; x=0;y=0; if(has_five(1)||has_five(2)) { return;//已经连成5子,什么都不做了 } if(can_five(color,x,y)) { return;//如果能连成5子,那么返回 } if(can_five(anticolor,x,y)) { return;//看对方能否连成5子 } if(has_alive(color,count,tempresult)) { //存在活子,直接输出活子(应从结果集中random选取) selectqianmodel5(color,x,y,tempresult,count); return; } if(has_twolevel_four(color,count,tempresult)) { //存在一个存在四子的二阶活子 selectqianmodel5(color,x,y,tempresult,count); return; } if(has_qianmodel_addone(color,count,tempresult,true)) { selectqianmodel5(color,x,y,tempresult,count); return; } if(has_qianmodel(colo

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论