Dotcpp  >  编程教程  >  C/C++游戏类项目  >  C语言实现五子棋游戏教程及代码

C语言实现五子棋游戏教程及代码

点击打开在线编译器,边学边练

一、源码简介

这是一个可以进行五子棋游戏的小程序,采用C语言进行编写。

上下左右控制光标位置,空格下子,黑白棋交替进行。

 编译环境:Dev-c++(采取纯C语言写法),没有调用第三方库,简单易学


二、运行截图

下棋时候界面,光标显示位置,空格下子

五子棋界面1

获胜后提示界面:

五子棋界面2



三、源码解析

先看主函数部分:

int main()
{
    system("title 五-子-棋"-- Dotcpp(dotcpp.com));//设置文件标题
    system("mode con cols=64 lines=32");//设置窗口大小
    system("color E0");//设置背景颜色
    while(1)
    {
        Gamerun();//Gamerun的每一次循环是进行一整局游戏
    }
    return 0;//实际用不上
}

为了实现游戏的运行,我们需要完成Gamerun这个函数。下面是函数的框架,也是这个游戏运行的具体流程

初始化变量

循环对局:

{

打印棋盘;

以下循环{

接收键盘输入

输入为esc,退出游戏

输入为方向键,改变光标位置

输入为空格,走子并判定胜负,分出胜负则跳出循环

}

处理胜利事件

}

具体为代码就是

void Gamerun()
{
    int input;//定义键盘输入字符
    Initialize();//初始化变量
    while(1)
    {
        Datatomap();//将对局信息输入缓冲变量
        Showcursor();//将光标加入缓冲变量
        Printmap();   //打印棋盘
        input=getch();//等待键盘输入指令
        if(input==27)exit(0); //若输入是Esc,退出游戏
        else if(input==32)//若输入空格,进行走子
        {
            if(Put())//走子成功
            {
                if(Check())break;//检查是否分出胜负
                else
                    now=3-now;//切换走子方
            }
            else;//走子失败
        }
        else if(input==0xE0)//如果按下的是方向键,会填充两次输入,第一次为0xE0表示按下的是控制键
        {
            Movecursor(getch());//利用第二次输入移动光标
        }
        else;
    }
    Showtest();//将胜利文字输入缓冲区
    Printmap();//打印棋盘
    getch();//输入任意键开始下一局游戏
}

getch()可以立即对输入的字符做出反应,而不像getchar()还要输入回车。

 

我们来详细看这几个步骤。

1. 初始化变量:随着项目的推进,我们自然会知道哪些数据需要初始化。先在这里放一个空函数。

void Initialize()
{  
}

2. 打印棋盘:

我们可以通过打印制表符的方式来拼接整个棋盘。自然,我们需要一个缓冲变量来存储整个棋盘的信息,这个变量又是对局信息经过转换得到的。

 

int data[LENGTH][LENGTH];//储存对局信息,0空白,1黑子,2白子

char map[LENGTH*2+1][LENGTH*2+1][5];//需要打印的棋盘,包括边框,子的位置,以及文字

(建议缓冲变量不要像我这么写。这个三维字符数组的本意是想构建一个二维的字符串组,但在后续的操作中,就会发现这引起了可能的麻烦。有条件的同学可以试试,改变这个变量的形式,看看这个程序应该怎么写。)

 

设定将对局信息转化为缓冲变量的函数

void Datatomap()//由对局信息生成棋盘信息
{
    int i,j;
    for(i=0;i<LENGTH*2+1;i++)
    {
        for(j=0;j<LENGTH*2+1;j++)
        {
            if(i==0&&j==0)strcpy(map[i][j]," ┏");
            else if(i==0&&j==LENGTH*2)strcpy(map[i][j]," ┓");
            else if(i==LENGTH*2&&j==0)strcpy(map[i][j]," ┗");
            else if(i==LENGTH*2&&j==LENGTH*2)strcpy(map[i][j]," ┛");
            else if(i==0&&j%2==0)strcpy(map[i][j]," ┯");
            else if(i==LENGTH*2&&j%2==0)strcpy(map[i][j]," ┷");
            else if((i==0||i==LENGTH*2)&&j%2==1)strcpy(map[i][j]," ━");
            else if(j==0&&i%2==0)strcpy(map[i][j]," ┠ ");
            else if(j==LENGTH*2&&i%2==0)strcpy(map[i][j],"┨");
            else if((j==0||j==LENGTH*2)&&i%2==1)strcpy(map[i][j]," ┃");
            else if(i%2==0&&j%2==0&&data[i/2][j/2]==0)strcpy(map[i][j],"┼ ");//注意棋盘变量的长度和棋局变量并不相同
            else if(i%2==0&&j%2==0&&data[i/2][j/2]==1)strcpy(map[i][j],"●");
            else if(i%2==0&&j%2==0&&data[i/2][j/2]==2)strcpy(map[i][j],"○");
            else if(i%2==0&&j%2==1)strcpy(map[i][j],"—");
            else if(i%2==1&&j%2==0)strcpy(map[i][j]," │");
            else
                strcpy(map[i][j],"  ");
        }
    }
}

 

设定打印棋盘信息的函数

void Printmap()//将棋盘信息打印至屏幕
{
    system("cls");//清理屏幕,准备写入
    int i,j;
    char line[100];//定义一个函数,存放当前输出行的数据
    for(i=0;i<LENGTH*2+1;i++)//逐行输出棋盘数据
    {
        strcpy(line,"");
        for(j=0;j<LENGTH*2+1;j++)
        {
            strcat(line,map[i][j]);//将输出拼接到该行的末尾
        }
        printf("%s",line);//打印该行的数据
        if(i<LENGTH*2)printf("\n");
        else;
    }
}这里设定每次打印一行的数据。如果利用双循环,调用printf次数过多,会变得很卡。

 

完成这一步之后,屏幕上应该已经能看到输出了。有可能字符的位置还是不大对,通过改变为map[i][j]赋值的函数内容,可以看出究竟是哪里出了问题,然后在适当的位置添加空格调整。

现在我们的成果是这样的。

棋盘效果

之后每做一步,也可以看看显示界面的变化,这样方便及时修正程序当中的错误。

 

3. 接收键盘输入并处理命令:

如果输入为Esc,退出程序。

if(input==27)exit(0); //若输入是Esc,退出游戏

如果输入为方向键,切换光标指示的位置。

else if(input==0xE0)//如果按下的是方向键,会填充两次输入,第一次为0xE0表示按下的是控制键
{
     Movecursor(getch());//利用第二次输入移动光标
}

这里需要定义一个函数,以显示光标位置。

void Showcursor()//在棋盘信息中加入光标位置
{
    strcpy(map[x*2-1][y*2-1]," ┏");
    strcpy(map[x*2-1][y*2+1]," ┓");
    strcpy(map[x*2+1][y*2-1]," ┗");
    strcpy(map[x*2+1][y*2+1]," ┛");//在光标的周围加入制表符
}

 

如果输入空格,执行走子程序。

else if(input==32)//若输入空格,进行走子
{
   if(Put())//走子成功
   {
         if(Check())break;//检查是否分出胜负
         else
          now=3-now;//切换走子方
   }
   else;//走子失败
}

 

4. 走子并且检验胜负

走子后,修改棋局变量,打印棋盘。

int Put()//走子
{
    if(data[x][y]==0)//若光标处无子
    {
        data[x][y]=now;//改变棋局数据
        Datatomap();//由对局数据生成棋盘信息
        Printmap;//打印棋盘
        return 1;
    }
    else
        return 0;
}

 

定义检验是否分出胜负的函数。

int Check()//检查从落子点出发,八个方向该类型棋子的数目
{
    int a=0,b=0,c=0,d=0,i;//四个方向上连续子的数目
    for(i=1;i<5;i++)
    {
        if(x+i>=0&&x+i<LENGTH&&data[x+i][y]==now)a++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(x-i>=0&&x-i<LENGTH&&data[x-i][y]==now)a++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y+i>=0&&y+i<LENGTH&&data[x][y+i]==now)b++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y-i>=0&&y-i<LENGTH&&data[x][y-i]==now)b++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y+i<LENGTH&&x+i<LENGTH&&data[x+i][y+i]==now)c++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y-i>=0&&x-i>=0&&data[x-i][y-i]==now)c++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y-i>=0&&x+i<LENGTH&&data[x+i][y-i]==now)d++;
        else break;
    }
    for(i=1;i<5;i++)
    {
        if(y+i<LENGTH&&x-i>=0&&data[x-i][y+i]==now)d++;
        else break;
    }
    if(a==4||b==4||c==4||d==4)return 1;
    else return 0;
}

 

5. 处理胜利事件

在胜利时需要一个表达文本的功能。设定一个函数,通过改变缓冲变量间接打印文字。

void Showtest()//胜利时加入文字
{
    if(now==1)
    {
        strcpy(map[15][14],"黑");
        strcpy(map[15][15],"胜");
        strcpy(map[15][16],"!");
    }
    else
    {
       strcpy(map[15][14],"白");
        strcpy(map[15][15],"胜");
        strcpy(map[15][16],"!");
    }
}

增加胜利文字,打印棋盘;输入任意键,重新开始游戏。

Showtest();//将胜利文字输入缓冲区
    Printmap();//打印棋盘
    getch();//输入任意键开始下一局游戏



四,完整代码下载

C语言五子棋源码下载  


本文固定URL:https://www.dotcpp.com/course/1227

趣味项目教程
第一章 C/C++游戏类项目
第二章 C/C++工具及其他类项目
第三章 Python趣味项目
Dotcpp在线编译      (登录可减少运行等待时间)