怎么编一个五子棋游戏?(带ai)

来源:互联网 发布:数据库管理系统语言 编辑:程序博客网 时间:2024/04/20 11:07

源代码下载

本教程适合初学者,用到的工具VC++ 6.0

 

五子棋游戏算法比较简单,实现起来比较容易,适合初学者练习。

    我这个五子棋游戏是自己花了2天的时间完成的,当时刚学mfc,想练一下手就做了这个游戏。

    棋盘和棋子可以用GDI来实现,棋盘用GDI划线,基本上就是LineTo(x,y),MoveTo(x,y),一个棋盘就出来了。具体代码如下

    OnPaint()函数的else内加入如下代码

 

       CPaintDC dc(this);

       dc.SelectStockObject(BLACK_PEN);

       int i,j;

       for(i=60;i!=420;i=i+40)

       {

           dc.MoveTo(i,60);

           dc.LineTo(i,380);

       }

       for(j=60;j!=420;j=j+40)

       {

           dc.MoveTo(60,j);

           dc.LineTo(380,j);

       }

    一个9×9的棋盘就画好了。至于如何画棋子,我思考了很长时间,贴图太麻烦,就用GDI来画圆,然后填充上不同的颜色,黑子、白子也就实现了。这里的棋子不应该是一个独立的量,它有自己的区域,应该能判断鼠标是不是点击到了这个区域,当点击这个区域的时候是否应该显示,应该显示什么颜色的旗子…… 把这么多东西集合在一起,应该定义一个类,于是CQuyu这个类就出现了。

    CQuyu有四个变量如下:

intflag;

    CRect rect;

    int y;

    int x;

x,y表示这个区域的中心,rect为以x,y为中心的边长为30的矩形,flag用来表示该对象的状态(0:空白 1:黑子 2:白字)

然后又定义了5个方法

    bool isWhite();//如果为白子,返回true

    CRect getRect();//获得该对象对应的CRect

    bool isBlack();//如果为黑子,返回true

    bool isEmpty();//如果为空,返回true

    bool isOn(CPoint point);//如果该点出在该区域返回true,用来判断鼠标单击对应的区域

   

view类中定义了一个vector容器,(需要包含#include <vector>

vector<CQuyu>qy;

OnInitDialog()内对qy进行初始化

    int i,j;

    CQuyu q;

    for(i=60;i!=420;i=i+40)

{

       for(j=60;j!=420;j=j+40)

       {

           q.x=i;

           q.y=j;

           qy.push_back(q);

       }

}

    当鼠标单击的时候,判断单击的是哪一个区域,如果该区域为空则修改区域状态

    void CWuziqidlgDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    int i;

    for(i=0;i!=qy.size();i++)

       if(qy[i].isOn(point)&&!over&&qy[i].isEmpty())

       {

           qy[i].flag=1;

           ison=1;

           break;

       }     

    Invalidate();//引发重绘

}

OnLButtonUp()中实现ai,电脑走棋

voidCWuziqidlgDlg::OnLButtonUp(UINT nFlags, CPoint point)

{

    // TODO: Add your message handler code hereand/or call default

    //flag 1:black 2:white

    //color 1:white 2:black

    int i,temp1,temp2,max1,max2;

    max1=0;

    max2=0;

    temp1=0;

    temp2=0;

    for(i=0;i!=qy.size();i++)

    {

       if(qy[i].isEmpty())

       {

           qy[i].flag=2;

           if(getScore(1)>max1)

           {

              temp1=getScore(1);

              max1=temp1;

              temp1=i;

           }

           qy[i].flag=1;

           if(getScore(2)>max2)

           {

              temp2=getScore(2);

              max2=temp2;

              temp2=i;

           }

           qy[i].flag=0;

       }

    }

    if(ison==1&&!over)

    {

       if(max1>=max2)

           qy[temp1].flag=2;

       else

           qy[temp2].flag=2;

    }

    ison=0;

 

 

    if(!isWin())

    Invalidate();

 

    CDialog::OnLButtonUp(nFlags, point);

}

OnPaint()函数中实现绘制,每次先把棋盘画好,然后遍历各区域,如果不为空就绘制相应的棋子。还要判断是否有一方获胜,如果有就结束游戏。(具体代码见源程序)

这个程序主关键的是算分,对不同的走法进行算法,得分最高的为要真正要走的。这也就是ai,这一点我参考了网上的五子棋经典算法(自己做了一些修改):

 

判断是否能成5, 如果能给予10500

判断是否能成活4,如果能给予10400

判断是否能成双死4,如果能给予10300

判断是否能成死43,如果能给予10000

判断是否已成双活3,如果能给予5000分,如果是人方的话给予-5000 分;

判断是否成死33,如果是机器方的话给予1000

判断是否能成死4,如果能给予500

判断是否能成单活3,如果能给予200

判断是否已成双活2,如果能给予100

判断是否能成死3,如果能给予50

判断是否能成双活2,如果能给予10

判断是否能成活2,如果能给予5

判断是否能成死2,如果能给予3

否则给0

 

下五子棋不光要进攻,还要防守,所以要先对假设那些空的格子下自己的棋子能得多少分,得出一个最高分,然后假设这些格子放上对方的棋子,得出一个最高分,如果进攻的最高分大于等于防守的最高分,则进攻,否则先进行防守。还有一些具体的细节没有写出,如怎么判断活4,活5之类的。这些问题比较简单,留给读者去思考。

 

我的源程序实现了上述所有功能,有疑问可以去看源代码。也可以直接和我联系,我的邮箱jianger2005@163.com

源代码下载