小白的编程经验(五子棋游戏)

学完函数,可以用函数来做一个五子棋小项目练练手。
项目代码放在了码云(gitee)上,有兴趣的可以下载看看。
https://gitee.com/YHF_200623/C_gobang

五子棋游戏

先简单介绍一下游戏,游戏玩法和传统的五子棋一样。通过输入坐标来选择下棋的位置,当有一方的棋子达到连续五颗及以上时,游戏结束,该玩家获胜。

黑棋为@,白棋为O ,空白处用 * 表示。

在这里插入图片描述

定义并初始化数据

需要的定义的数据有:

  • 定义棋盘数组 15*15
  • 定义角色变量
  • 定义变量用于记录下棋位置

棋盘没什么好说的,定义一个15*15的数组,初始化为0就好了。角色变量我采用的是1和-1,这样设置在切换角色时会很方便。
最后在定义两个变量来接收键盘输入的坐标值。为了使用方便,将它们都定义为全局变量,这样可以省去参数传递的过程。

char Arr[15][15] = {};
char X = 0,Y = 0;
char Now = -1;

清屏并打印棋盘

下面写一下显示棋盘的函数,其实就是遍历迷宫数组,在打印时判断输出对应的字符,用两层for循环加switch语句即可。在这里我把在打印时判断输出对应的字符也作为一个单独的函数print()。linux系统可以使用函数system调用系统命令clear,实现清屏效果,需要调用头文件stdlib.h。windows系统需要使用windows.h头文件,里面的清屏命令改成cls。由于差别不大,就以linux系统的为例,windows系统的自己稍微修改一下。

char print(char n)
{
    char ch = ' ';
    switch(n)
    {
        case 0: ch = '*'; break;
        case 1: ch = '@'; break;
        case -1: ch = 'O'; break;
    }
    return ch;
}

void show(void)
{
    system("clear");
    printf("  ");
    for(int i=0;i<15;i++)
    {
        printf(" %2d",i);
    }
    printf("\n");
    for(int i=0;i<15;i++)
    {
        printf("%2d ",i);
        for(int j=0;j<15;j++)
        {
            printf(" %c ",print(Arr[i][j]));
        }
        printf("\n");
    }
}

判断是否五子连珠

判断是否五子连珠可以分类讨论,分成横、纵、左上到右下、右上到左下四种情况,每种情况又大同小异。我的思路是缩小范围,只考虑当前坐标的前四个棋子和后四个棋子,从前四个棋子遍历到后四个棋子,如果该棋子与下一个棋子都为当前角色的下的棋(黑棋或白棋),计数加一。一旦中间出现其他棋子或者空白,计数中断并重新计数。当计数到达5时,可以得出结论:该玩家获胜。若没有则判断其他情况。当其他情况也不满足时,就返回失败,下一个玩家继续落子。
注意:下面这段代码不能运行,因为全局变量没有大写。这段代码仅供参考,后面有优化的代码,可以直接运行。如果需要尝试,请自己修改一下。

int judge(void)
{
    int cunt = 1;
    for(int i=x-4;i<=x+4;i++)
    {
        if(i<0)
        {
            continue;
        }
        if(i>=14)
        {
            break;
        }
        if(arr[i][y] == now && arr[i+1][y] == now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt == 5)
        {
            printf("%c棋获胜",print(now));
            return now;
        }
    }
    for(int i=y-4;i<=y+4;i++)
    {
        if(i<0)
        {
            continue;
        }
        if(i>=14)
        {
            break;
        }
        if(arr[x][i] == now && arr[x][i+1] == now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt == 5)
        {
            printf("%c棋获胜",print(now));
            return now;
        }
    }
    for(int i=-4;i<=4;i++)
    {
        if(x+i<0)
        {
            continue;
        }
        if(x+i>=14)
        {
            break;
        }
        if(arr[x+i][y+i] == now && arr[x+i+1][y+i+1] == now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt == 5)
        {
            printf("%c棋获胜",print(now));
            return now;
        }
    }
    for(int i=-4;i<=4;i++)
    {
        if(x+i<0)
        {
            continue;
        }
		if(x+i>=14)
        {
            break;
        }
        if(arr[x+i][y-i] == now && arr[x+i+1][y-(i+1)] == now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt == 5)
        {
            printf("%c棋获胜",print(now));
            return now;
        }
    }
    return 0;
}

可以看到,这个判断函数很长,而且很多都是重复的代码。因此可以做优化,也可以采用偏移量的方法进行优化。

int judge(int a,int b)
{
    int cunt = 1;
    for(int i=-4;i<=4;i++)
    {   
        if(X+i<0||Y+i<0)
        {
            continue;
        }
        if(X+i>=14||Y+i>=14)
        {
            break;
        }
        if(Arr[X+i*a][Y-i*b] == Now && Arr[X+(i+1)*a][Y-(i+1)*b] == Now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt >= 5)
        {
            printf("%c棋获胜",print(Now));
            return Now;
        }
    }   
    return 0;
}

这样就可以把四个方向的代码统一成一个函数,通过传入不同的参数,实现不同方向的判断。

落子

落子时,使用scanf函数从键盘中接收到值传入X,Y中。并且判断改坐标点是否越界,同时需要满足该点为空白点,可以落子。否则输出提示信息,并重新调用此方法,直到遇到合法输入,将该点设置为当前角色的棋子。

代码如下

	void act(void)
{
    printf("请输入%c棋子的坐标:",print(Now));
    scanf("%hhd%hhd",&X,&Y);
    if(!(X>=0 && X<=14 && Y>=0 && Y<=14 && Arr[X][Y] == 0)) 
    {   
        printf("该坐标不能落子,请重新输入。\n");
        act();
    }   
    else
    {   
        Arr[X][Y] = Now;
    }   
}

确定获胜条件

什么时候游戏算结束了呢,当在目标点处箱子数量等于4个,游戏就结束了。统计箱子数量可以放在显示地图的循环里,当箱子在目标点处(值为7),cnt++。因此可以写出游戏结束的条件:

	//结束判断
 	if(4 == cnt)
    {
        printf("游戏结束\n");
        return 0;
    }

主函数调用

我们现在已经实现的功能有:

  1. 棋盘并显示棋盘
  2. 判断五子连珠
  3. 落子

游戏大部分的代码都在这里了,我们需要对它们进行组装使用即可。先捋一捋游戏流程:

  1. 清屏并显示地图
  2. 判断五子连珠
  3. 落子
  4. 回到第一步

根据游戏流程,可以看出需要使用死循环。在每次循环清屏并显示棋盘。然后判断五子连珠,如果获胜就退出,否则游戏继续,交换角色下棋。通过获取键盘输入的坐标,判断是否可以落子。成功落子后进入下一次循环。

int main(int argc,const char* argv[])
{
    while(1)
    {
        show();
        if(!(judge(0,1) || judge(1,0) ||judge(1,-1) ||judge(1,1)))
        {
            Now = - Now;
        }
        else
        {
            return 0;
        }
        act();
    }
}

组合代码

将上述代码组合,即可获得下面代码(只能在运行linux中运行,windows需要修改,下面会提到)

#include<stdio.h>
#include<stdlib.h>

char Arr[15][15] = {}; 
char X = 0,Y = 0;  
char Now = -1; 

char print(char n); 
void show(void);
void act(void);
int judge(int a,int b); 

int main(int argc,const char* argv[])
{
    while(1)
    {   
        show();
        if(!(judge(0,1) || judge(1,0) ||judge(1,-1) ||judge(1,1)))
        {
            Now = - Now;
        }
        else
        {
            return 0;
        }
        act();
    }   
}

char print(char n)
{
    char ch = ' ';
    switch(n)
    {   
        case 0: ch = '*'; break;
        case 1: ch = '@'; break;
        case -1: ch = 'O'; break;
    }   
    return ch; 
}

void show(void)
{
    system("clear");
    printf("  ");
    for(int i=0;i<15;i++)
    {
        printf(" %2d",i);
    }
    printf("\n");
    for(int i=0;i<15;i++)
    {
        printf("%2d ",i);
        for(int j=0;j<15;j++)
        {
            printf(" %c ",print(Arr[i][j]));
        }
        printf("\n");
    }
}

void act(void)
{
    printf("请输入%c棋子的坐标:",print(Now));
    scanf("%hhd%hhd",&X,&Y);
    if(!(X>=0 && X<=14 && Y>=0 && Y<=14 && Arr[X][Y] == 0))
    {
        printf("该坐标不能落子,请重新输入。\n");
        act();
    }
    else
    {
        Arr[X][Y] = Now;
    }
}

int judge(int a,int b)
{
    int cunt = 1;
    for(int i=-4;i<=4;i++)
    {
		if(X+i<0||Y+i<0)
        {
            continue;
        }
        if(X+i>=14||Y+i>=14)
        {
            break;
        }
        if(Arr[X+i*a][Y-i*b] == Now && Arr[X+(i+1)*a][Y-(i+1)*b] == Now)
        {
            cunt++;
        }
        else
        {
            cunt = 1;
        }
        if(cunt >= 5)
        {
            printf("%c棋获胜",print(Now));
            return Now;
        }
    }
    return 0;
}

windows 使用系统命令清屏,里面的清屏命令改成cls。

结语

希望这篇文章对你有所帮助

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值