“欢乐五子棋”——C++程序设计(探索者校刊)

[日期:2019-06-03] 作者:信息技术 次浏览 [字体: ]

2020年级3班 刁俊熙   指导教师:旷勇


假日闲暇,无所事事,便想寻一个事情来做,正好在学C++,于是决定做一个程序来练手。由于近日迷上了五子棋,尤其喜欢和同学较量,“欢乐五子棋”这个程序就随之应运而生。

首要的两个基本问题是棋盘的打印和已落棋子的储存。解决方法也十分巧妙:若将棋盘看作一个直角坐标系,每颗棋的位置就可以用一组坐标值表示出来,而一个二维数组恰好可以满足这个需求,数组的两个维度分别对应棋盘上的横纵坐标。这样做的好处是不仅解决了棋子的储存问题,而且打印棋盘也可以通过遍历整个数组进行逐个输出来轻松实现。无须采用gotoxy)函数(Turbo C,其他编译器中需要利用Windows API自行实现),落一个棋子,移动光标到指定位置输出一个。

     在下棋时,考虑到用户的输入可能千奇百怪,不按照标准走,故可用一个死循环把下棋的部分嵌套起来,当输入符合标准后退出循环,否则一直让你重新输入直到正确为止。若棋盘大小为a*b,则棋子坐标(x,y)应满足

                       

计算机判断输赢,就要判断五子是否连珠,这时候只要判断某一个棋子在八个方向上和相邻的另外四个棋子颜色是否一致。而在棋盘中,上下,左右,左上右下,左下右上是重复的,因此八个方向就可以简化为四个方向。但是很可惜,计算机是无法判断棋盘上的方向的。这可难不倒我,同样可以利用二维数组的原理来实现,例如这句代码就可以判断棋盘在纵坐标上是否出现了五子连珠的情况。if (me[a][b]==me[a][b+1]&&me[a][b]==me[a][b+2]&&me[a][b]==me[a][b+3]&&me[a][b]==me[a][b+4]&&me[a][b]==1) return 1 你看懂了吗?其实很简单,就是判断当横坐标x=a时,纵坐标上连续五个棋子的颜色值是否相同。

至此,玩家与玩家的对弈功能已经可以实现了,但这个五子棋程序的设计并不会止步于此。在没有小伙伴同我玩时,一个人无法下棋,就可以设计一个AI来陪我过过棋瘾!在这之前,应该先告诉AI什么时候该进攻或者防守,如何制胜。于是我在网上查找了五子棋的基本棋型:

1.连五:五颗相同颜色的棋子连在一起   ●●●●●

2.活四:四颗相同颜色的棋子连在一起,且有两个点可以形成连五 _●●●●_

3.冲四:有且只有一个点可以使四颗颜色相同的棋子连成连五

_●●●●○、●_●●●、●●_●●

4.活三:可以形成活四的三颗颜色相同的棋子

        _●●●___●●_

5.眠三:可以形成冲四的三颗颜色相同的棋子

        _●●●○、_●●_●○、__●●○、○_●●●_○、●●_ _●、●__

6.活二:可以形成活三的两颗颜色相同的棋子

       _ _●●_ ______ __

7.眠二:可以形成眠三的两颗颜色相同的棋子

_ _ _●●○、_ __●○、__ ●○、●_ _ _

这些棋型的权重大小关系为:连五>活四>冲四>活三>活二>眠三>眠二

接下来最关键的是教会AI判断当前局势,找到最佳着棋点,称为估值。此时可以引入一个函数int envaluate(int x,int y),其中x,y是估值点的坐标。这时只要在函数定义中加入各种棋型的判断,遍历整个二维数组。把每个点的坐标传入同时计算返回一个权重值,所有可落子的坐标的权重进行逐一比较而得出一个最佳着棋点。进攻和防守两种情况分别进行分析,最后再把两个的权重作比较,就能得出是该进攻还是防守。但这样也有一个缺点,AI每次下棋都仅仅着眼于当前这一步棋的最佳选择。如果要让它预判未来若干步,并且得出比最佳“更佳”的选择,则需要在当前局势下,任意位置试下棋并再次分析权重,如此递归,选择出最好的一个抉择。

参考文献:https://baike.baidu.com/item/%E4%BA%94%E5%AD%90%E6%A3%8B/130266#viewPageContent

编译环境:Windows 7 64 dev-cpp 5.11  gcc 4.9.2

附:部分代码如下。

int main()

{

         int score;

         int res;

         cout << "欢迎来到五子棋\n" << "按任意键开始"; cin.get();

                   while (res = 2)

                   {

                            system("cls");

                            for (int arri = 0; arri < 15; arri++)

                            {

                                     for (int arri1 = 0; arri1 < 15; arri1++)

                                     { me[arri][arri1] = 0; }

                            }

                            while (225)

                            {

                                     display();

                                     putq();

                                     score = judge();

                                     if (score == 1)

                                     {  cout << "玩家1胜利";  break;  }

                                     else if (score == 2)

                                     {  cout << "玩家2胜利";  break;  }

                                     else if (score == 3)

                                     {  cout << "平局";  break;  }

                                     x = y = 0;

                            }

                            if (score == 0)

                                     cout << "平局";

                            cout << "重新开始请输入1,退出游戏请输入2.";

                   zc:(cin >> res).get();

                            if (res == 1) continue;

                            else if (res == 2) break;

                            else

                            {

                                     cout << "请输入正确的字符!" << endl;

                                     goto zc;

                            }

                   }

         return 0;

}