猴子也会懂的C语言五子棋的实现方法详解

​ 正在学习C语言的博主自编了一个五子棋程序,下边将自己在coding中遇到的一些问题与解决办法发出来,以求帮助和博主一样迷茫的C语言入门者

​ 代码如下(有些凌乱,重要部分在下边都有解说哦:-))

#include<stdio.h>                         //定义:奇数回合为米方回合,偶数回合为圈方回合//
#include<windows.h>
HANDLE hout;
COORD coord;
int test,test1;
char QP[15][15],stop,stop2;
int i,o,j;
int a,b;
int turn;
int move_();
int main()
{
    int token;
    turn=1;
    coord.X=0;
    coord.Y=0;
    hout=GetStdHandle(STD_OUTPUT_HANDLE);
    test=1;
    test1=1;
    printf("你正在玩一个叫做五子棋的古老游戏\n");
    printf("按回车进行游戏");
    stop=getch();
    system("cls");
    if(stop!=13)
    {
        printf("爱玩不玩!");
        test=0;
        printf("\n你可以按任意键滚");
        stop=getch();
    }
    system("cls");
    for(i=0;i<15;i++)
    {
        for(o=0;o<15;o++)
        {
            QP[i][o]='+';
        }
    }
    while(test==1)                         //游戏循环//
    {
        for(i=0;i<15;i++)             //通过双重循环打印棋盘//
        {
            for(o=0;o<15;o++)
            {
                printf("%c ",QP[i][o]);
            }
            printf("\n");
        }
        printf("\n先走的是\"*\",你叫星星\n后走的是\"o\",你叫圈圈");
        a=move_();
        //打印完毕 下边进行胜负判断,原理大概是通过依次判断相邻五个位置的值是否相等//
        for(i=0;i<15;i++)//验证横排//
        {
            for(o=0;o<9;o++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[i][o]==QP[i][o+j]&&QP[i][o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }

            }
        }
        for(o=0;o<15;o++)//验证竖排//
        {
            for(i=0;i<9;i++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[i][o]==QP[i+j][o]&&QP[i][o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }

            }
        }
        for(i=4;i<=14;i++)//验证'/'对角线//
        {
            test1=i-3;     //对于每个斜行需要验证的次数//
            for(o=0;o<test1;o++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[0+o][i-o]==QP[0+o+j][i-j-o]&&QP[0+o][i-o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }
            }
        }
        for(i=1;i<=10;i++)
        {
            test1=10-i;     //对于每个斜行需要验证的次数//
            for(o=0;o<test1;o++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[14-o][i+o]==QP[14-o-j][i+j+o]&&QP[14-o][i+o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }
            }

        }
        for(i=0;i<=10;i++)//验证'\'对角线//
        {
            test1=11-i;     //对于每个斜行需要验证的次数//
            for(o=0;o<test1;o++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[o][i+o]==QP[o+j][i+j+o]&&QP[o][i+o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }
            }
        }
        for(i=4;i<=13;i++)
        {
            test1=i-3;     //对于每个斜行需要验证的次数//
            for(o=0;o<test1;o++)
            {
                token=0;
                for(j=1;j<=4;j++)
                {
                    if(QP[14-o][i-o]==QP[14-o-j][i-o-j]&&QP[14-o][i-o]!='+')
                        token++;
                    if(token==4)
                        test=0;
                }
            }

        }
        if(test==0)
        {
            system("cls");
            for(i=0;i<15;i++)             //通过双重循环打印棋盘//
            {
                for(o=0;o<15;o++)
                {
                    printf("%c ",QP[i][o]);
                }
                printf("\n");
            }
            turn--;
            coord.X=0;
            coord.Y=15;
            SetConsoleCursorPosition(hout,coord);
            if(turn%2==0)
                printf("圈圈赢了!");
            else
                printf("星星赢了!");
            printf("\n按键继续");
            stop=getch();
        }
        system("cls");
    }
}
int move_()
{
    b=1;
    while(b==1)
    {
        SetConsoleCursorPosition(hout,coord);
        char ch1,ch2;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        GetConsoleScreenBufferInfo(hout,&csbi);
        ch1=getch();
        if(ch1==-32)
        {
            ch2=getch();
            switch(ch2)
            {
                case 72:
                    if(coord.Y!=0)
                        coord.Y=coord.Y-1;
                    else
                        coord.Y=14;
                    break;
                case 75:
                    if(coord.X!=0)
                        coord.X=coord.X-2;
                    else
                        coord.X=28;
                    break;
                case 77:
                    if(coord.X!=28)
                        coord.X=2+coord.X;
                    else
                        coord.X=0;
                    break;
                case 80:
                    if(coord.Y!=14)
                        coord.Y=1+coord.Y;
                    else
                        coord.Y=0;
                    break;
            }
            SetConsoleCursorPosition(hout,coord);
        }
        if(ch1==13)
        {
            int X=0;
            X=coord.X/2;
            if(turn%2==0)
                QP[coord.Y][X]='O';
            else
                QP[coord.Y][X]='*';
            b=0;
            turn++;
        }
    }
    return 0;
}

这里主要总结一下在程序设计中遇到的两个难点:

​ 1.光标控制与方向键的识别

​ 2.胜负判断

解决办法

​ 光标控制使用了头文件window.h自带的函数(由于所学甚浅,这部分主要靠百度,不过百度上的方法还是多少有点杂乱,没有解释,我尽量用简单的语言概括一下.

用到的相关windows.h知识有:

函数:

GetStdHandle(STD_OUTPUT_HANDLE)用在main函数中,作用是从窗口中读取标准输入的句柄(句柄概念本人不太了解,这里说的是本人的理解).

GetConsoleScreenBufferInfo(hout,&csbi)使用设置光标坐标函数的前提.

SetConsoleCursorPosition(hout,coord)设置光标坐标

类:

句柄:如HANDLE hout :调用windows中关于

COORD:内含两个整形变量,分别为xxx.X和xxx.Y(xxx是类的名称)

概括来讲只要包含上述函数后即可通过SetConsoleCursorPosition(hout,coord)随意改变光标位置;

方向键的识别

原理:方向键的键码:上-3272 左:-3275 下:-3277 右:-3280(十进制)

    char ch1,ch2;
    ch1=getch();
    if(ch1==-32)
    {
        ch2=getch();
        switch(ch2)
        {
            case 72:
                if(coord.Y!=0)
                    coord.Y=coord.Y-1;
                else
                    coord.Y=14;
                break;
            case 75:
                if(coord.X!=0)
                    coord.X=coord.X-2;
                else
                    coord.X=28;
                break;
            case 77:
                if(coord.X!=28)
                    coord.X=2+coord.X;
                else
                    coord.X=0;
                break;
            case 80:
                if(coord.Y!=14)
                    coord.Y=1+coord.Y;
                else
                    coord.Y=0;
                break;
        }

​ 声明两个char变量ch1与ch2(由于char的最大值为一个char不能完全接受方向键的键值所以需要两个才能完全接收一个方向键并进行判定),接收方向键的ASCII码后进行两次判断,判定玩家按了哪个方向键,并对坐标进行改变,在后一步中通过SetConsoleCursorPosition将光标位置改变.当然还需要判断光标是否超出棋盘的范围. :-)

胜负判断

​ 对于五子棋这样一个入门性的程序,网络中常见的胜负判断方式有两种,一种是通过直接扫描一遍棋盘判定有没有连着五个的棋子,一种是直接扫描上一个落下的棋子周围的棋子有无连成串的棋子.本程序采用了第一种判断方式,相比第二种确实在计算上略显复杂,但好在相比第二种方法更适合像博主这样的小白实现.关于第二种方法可以参考百度,上边有很详细的解释.下边关于第一种办法进行详解.

    for(i=4;i<15;i++)//验证横排//
    {
        for(o=0;o<9;o++)
        {
            token=0;
            for(j=1;j<=4;j++)
            {
                if(QP[i][o]==QP[i][o+j]&&QP[i][o]!='+')
                    token++;
                if(token==4)
                    test=0;
            }

        }
    }

​ 验证横排的办法非常简单,这里声明一个变量token进行标记,每次用开始的棋子与后边四个棋子分别比较,若五个棋子相等则token将等于4,此时改变游戏循环的条件使游戏循环终止.用i表示排,o表示行即可遍历所有的横排连着五个棋子的组合.验证竖排时比葫芦画瓢即可.

当然要注意开始的棋子不能等于’+’!

​ 验证斜排的办法要稍微麻烦,下面是检验/方向的代码.

    for(i=4;i<=14;i++)//验证'/'对角线//
    {
        test1=i-3;     //对于每个斜行需要验证的次数//
        for(o=0;o<test1;o++)
        {
            token=0;
            for(j=1;j<=4;j++)
            {
                if(QP[0+o][i-o]==QP[0+o+j][i-j-o]&&QP[0+o][i-o]!='+')
                    token++;
                if(token==4)
                    test=0;
            }
        }
    }
    for(i=1;i<=10;i++)
    {
        test1=10-i;     //对于每个斜行需要验证的次数//
        for(o=0;o<test1;o++)
        {
            token=0;
            for(j=1;j<=4;j++)
            {
                if(QP[14-o][i+o]==QP[14-o-j][i+j+o]&&QP[14-o][i+o]!='+')
                    token++;
                if(token==4)
                    test=0;
            }
        }

    } 

​ 不短,对吧,因为对于一个15x15的正方形点阵来说,它一共有15+15-1个斜排!,好在因为有8个斜排因为容纳棋子数不超过4个可以不予考虑;那也还有21个! 所以我们将这些斜排通过对角线分成两个部分,通过两个循环解决问题!看着也不麻烦嘛!胜负判断到此结束!

​ 好了,接下来要做的就只有调整程序的结构,让你的新游戏显得更聪明,更有交互性,比如给它加上一个启动画面,加上几个小彩蛋了!大工告成!

​ 欢迎在评论里与博主进行讨论,以后博主还会写更多更深入的代码与大家交流,愿与大家在学习编程的道路上共同进步! :-0 BYE~

​ PS:这个程序有一个小小的有趣BUG,你能发现吗?

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值