五子棋人机对战,AI很低,做参考用,仅仅为大家提供一下思路。如果有什么好的建议或发现什么问题,希望能告诉我,我的邮箱是caoweizhou@163.com开发环境:VisualC++6.0游戏界面:C语言游戏2-五子棋(人机对战)一、开始工作...................................................................................................................................2二、画图...........................................................................................................................................5三、下棋...........................................................................................................................................8四、判断胜负.................................................................................................................................10五、人工智能.................................................................................................................................13六、附加功能.................................................................................................................................17一、开始工作新建工程,选MFCAppWizard(exe),添上工程名,确定。选基于对话框,完成,确定。插入位图网上的源码一般都是将棋盘和棋子用画图程序画出来,但我不会弄。我的方法是直接贴图。先插入位图(BMP格式),以下是我用的位图,当然你也可以用自己的位图:插入位图流程:有时会弹出下面这个窗口,这是完全没有问题的:位图插入后会自动赋予ID值,我们可以修改一下:二、画图///////////////////////////Draw函数/////////////////////////////////////////添加成员函数Draw:Draw(intx,inty,UINTbitmap,CDC*pDC)解释一下:x,y是画图的坐标bitmap是图片ID,比如我的黑棋图片ID就是IDB_BLACKpDC是显示图片窗口的句柄我的画图函数是下面这样的,其中要注意两个函数BitBlt和TransparentBlt,程序后有解释:voidCMyDlg::Draw(intx,inty,UINTbitmap,CDC*pDC){//装载图片CBitmapm_bmp;m_bmp.LoadBitmap(bitmap);//创建画布,比如要在窗口显示,则pDC为窗口句柄CDCdc;dc.CreateCompatibleDC(pDC);//将位图选到dc中,顺便保存画刷到pOldbmp//保存画刷、恢复画刷为规范操作,但可以不用CBitmap*pOldbmp=dc.SelectObject(&m_bmp);//创建bm,用来获取图片信息,这里是为了获取图片尺寸BITMAPbm;m_bmp.GetObject(sizeof(BITMAP),&bm);//画图if(IDB_BOARD==bitmap)//画棋盘pDC-BitBlt(x,y,bm.bmWidth,bm.bmHeight,&dc,0,0,SRCCOPY);else{//每个图片里有4X4个棋子,我只要画出一个就行了intw=bm.bmWidth/4;inth=bm.bmHeight/4;TransparentBlt(pDC-m_hDC,x,y,w,h,dc.m_hDC,0,0,w,h,RGB(255,255,255));}dc.SelectObject(pOldbmp);//恢复画刷}pDC-BitBlt(x,y,bm.bmWidth,bm.bmHeight,&dc,0,0,SRCCOPY);功能是贴图:将dc中的位图,截取大小bm.bmWidth,bm.bmHeight,粘贴到pDC所指的设备,贴图坐标x,y。最后一个参数为粘贴方式,我们是直接粘贴,所以是SRCCOPYTransparentBlt(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,粘贴到pDC所指的设备,贴图坐标x,y,贴图大小为w,h,如果图片大小不符则拉伸或压缩图片。最后一项是背景色,可以将图片背景透明化。使用TransparentBlt必须包含头文件和类库,否则编译错误:#includewingdi.h#pragmacomment(lib,msimg32.lib)函数弄好后就调用这个函数画图了。先在OnInitDialog函数中加入以下代码,调整对话框大小,并隐藏按钮://TODO:AddextrainitializationhereMoveWindow(0,0,520,540);//窗口定位CenterWindow();//居中窗口GetDlgItem(IDOK)-ShowWindow(SW_HIDE);GetDlgItem(IDCANCEL)-ShowWindow(SW_HIDE);或者直接在资源窗口中调整对话框:然后在OnPaint函数中加入以下代码画图:CDC*pDC=GetDC();//获取当前窗口句柄Draw(13,13,IDB_BOARD,pDC);//画棋盘//Draw(0,0,IDB_BLACK,pDC);//画黑棋,只是为了查看显示效果调整一下界面,希望你没有强迫症,可不要在调整上花太多时间了。下面是我做出的效果:三、下棋现在要将棋子准确下到各个点上,我用的棋盘,间距为34,点击鼠标时获取点击坐标x,y,然后x/34,y/34,确定棋子下到了哪个点上。////////////////////////OnLButtonUp函数///////////////////////////////////添加消息处理函数:我用的消息是WM_LBUTTONUP,也就是当鼠标左键抬起来的时候,函数响应:以下是函数代码:voidCMyDlg::OnLButtonUp(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefaultif(point.x0&&point.x480&&point.y0&&point.y480){intj=point.x/34;inti=point.y/34;intx=j*34;inty=i*34;CDC*pDC=GetDC();//获取当前设备句柄Draw(x,y,IDB_BLACK,pDC);}CDialog::OnLButtonUp(nFlags,point);}函数中,point.x,point.y为点击鼠标时的坐标现在可以将棋子准确地下到点上了,可是就算点上有已经有棋子了,点鼠标后也会下棋。所以我们用一个二维数组存储棋盘上的棋子。添加成员变量:初始化成员变量,在OnPaint函数里加入下面代码。画完棋盘的同时,初始化棋盘。for(inti=0;i15;i++)for(intj=0;j15;j++)chess[i][j]=0;修改OnLButtonUp函数中的下棋代码原来是直接用Draw(x,y,IDB_BLACK,pDC);画棋,现在改成下面的内容,当点上没有棋时才下棋:if(0==chess[i][j]){Draw(x,y,IDB_BLACK,pDC);chess[i][j]=1;//下的黑棋,这一点变成1}下棋功能完成了。四、判断胜负////////////////////////////iswin函数/////////////////////////////////////////先添加一个BOOL类型的成员函数iswin(inti,intj),每下一个棋子都通过这个棋子判断是否赢了。是则返回TRUE(或1),否则返回FALSE(或0)。默认返回FALSE。在OnLButtonUp函数中调用iswin。如果赢了弹出窗口我赢了,结束战斗!,初始化棋盘:voidCMyDlg::OnLButtonUp(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefaultif(point.x0&&point.x480&&point.y0&&point.y480){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_BLACK,pDC);chess[i][j]=1;}//判断输赢if(iswin(i,j)){MessageBox(我赢了,结束战斗!,提示,MB_OK);Invalidate(FALSE);}}CDialog::OnLButtonUp(nFlags,point);}MessageBox弹出窗口我赢了,结束战斗!Invalidate(FALSE)会放出一个WM_PAINT消息,间接调用OnPaint函数,初始化棋盘。/////////////////////////////search函数//////////////////////////////////////那到底怎么判断输赢呢?我采用的是下面这个方法:申明变量alive1,alive2,用来判断活棋还是死棋。申明变量count用来判断连子的个数。以横向四子为例,我刚下了第三个棋子。先从第三个棋子位置开始,往右边扫描,如果下的也是黑棋,则count++。如果遇到的不是黑棋,判断是不是空地。如果是空地alive1=1,表示右边一头是活的。否则alive=0。然后回到第三子位置,往左边扫描。对于扫描,我这里添加一个成员函数search用来扫描代码比较长,注意不要出错了,不然调试很麻烦的。intCMyDlg::search(inti,intj,intm,intn){inttempi,tempj,count=-1;intalive1=0,alive2=0;//第一次扫描tempi=i;tempj=j;while(tempi0&&tempi15&&tempj0&&tempj15&&chess[tempi][tempj]==chess[i][j]){tempi+=m;tempj+=n;count++;}if(chess[tempi][tempj]==0)alive1=1;//第二次扫描tempi=i;tempj=j;while(tempi0&&tempi15&&tempj0&&tempj15&&chess[tempi][tempj]==chess[i][j]){tempi-=m;tempj-=n;count++;}if(chess[tempi][tempj]==0)alive2=1;if(count=5)