万字解析:带你走进五子棋(普通版)和三子棋的世界(C语言)

C_Ryson 2021-12-01 15:23:25

原地址:(55条消息) 万字解析:带你走进五子棋(普通版)和三子棋的世界(C语言)_C_Ryson的博客-CSDN博客

今天,我们来再来实现一个大家都不陌生的小项目:三子棋。

1,三子棋
1,思路分析
写一个小项目,必不可少的是思路的构建。写一个游戏,我们首先需要一个菜单,这是最基本的,让用户来选择是否要玩这个游戏。如果要玩,就进入游戏主体的部分,不玩就直接退出。最简单的思路就是这样,而后一些细节的实现,比如游戏主体的实现需要在过程中配合去讲。

这里,我们将用到自己创建的头文件,以及多个.c文件,主要为了避免主函数中过于繁杂,庞大,我们将大部分功能封装成函数来实现。

2,代码实操
game.h文件中
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define ROW 3
#define COL 3
void Initialboard(char board[ROW][COL], int row, int col);
void Displayboard(char board[ROW][COL], int row, int col);
void playeremove(char board[ROW][COL], int row, int col);
void computermove(char board[ROW][COL],int  row,int col);
char Iswin(char board[ROW][COL], int  row, int col);
char Isfull(char board[ROW][COL], int row, int col);
这里可以看到,我们将一些函数都放到这里声明,包括需要用到的一些库函数的头文件,这样,我们在.c文件中就只需要包含我们自己写的头文件就可以,简化程序。当然,不要忘记引用自己写的头文件需要使用双引号""

game.c文件
#include"game.h"
//初始化棋盘
void Initialboard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++)
        {
            board[i][j] = ' ';
        }
    }
}
//打印棋盘
//   |   |   
//---|---|—-
//   |   |   
//---|—-|---
//   |   |   
void Displayboard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {   
        if (i == 0)
        {
            for (j = 0; j < col; j++)
            {
                if (j == 0)
                    printf("  %d  ",j);
                else
                    printf(" %d  ", j);
            }
            printf("\n");
        }
        printf("%d",i);
        for (j = 0; j < col; j++)
        {
            printf(" %c ", board[i][j]);
            if (j < (col - 1))
            {
                printf("|");
            }
                
        }
        printf("\n");
        if (i<row - 1)
        {
            for (j = 0; j < col; j++)
            {
                if (j==0)
                printf(" ---");
                else
                    printf("---");
                if (j < (col - 1))
                    printf("|");
            }
        }
        printf("\n");
    }
}
//实现玩家下棋
void playermove(char board[ROW][COL], int row, int col)
{
    int i, j;
    printf("请根据图示输入要走的坐标:");
    while (1)
    {   
        scanf("%d%d",&i,&j);
        if (i >= 0 && i < 3 && j >= 0 && j <3 && board[i][j] == ' ')
        {
            board[i][j] = '*';
            break;
        }
        else
            printf("输入有误,请重新输入。");
    }
}
 
void computermove(char board[ROW][COL], int  row, int col)
{
    while (1)
    {
        int i = rand() % row;
        int j = rand() % col;
        if (board[i][j] == ' ')
        {
            board[i][j] = '#';
            break;
        }
    }
}
 
char Iswin(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col - 2; j++)
        {
            if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] && board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (j = 0; j < col; j++)
    {
        for (i = 0; i < row - 2; i++)
        {
            if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (i = 0, j = 0; i < row - 2 && j < col - 2; i++, j++)
    {
        if (board[i][j] == board[i + 1][j+1] && board[i + 1][j+1] == board[i + 2][j+2] && board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    for (i = row-1, j = 0; i >=0 && j < col-2; i--, j++)
    {
        if (board[i][j] == board[i -1][j + 1] && board[i - 1][j + 1] == board[i -2][j + 2] && board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    return 'c';
}
char Isfull(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col;j++)
        {
            if (board[i][j] == ' ')
                return 'c';
        }
    }
    return 'e';
     
}
三子棋.c文件
#include"game.h"
//说明:
//*是玩家走的棋子
//#是电脑走的棋子
void menu()
{
    printf("*****************\n");
    printf("**1,play 0,exit**\n");
    printf("*****************\n");
    printf("请选择:");
}
void game()
{
    char win = 'c';
    char board[ROW][COL] = { 0};//创建棋盘
    Initialboard(board, ROW, COL);//初始化棋盘
    Displayboard(board, ROW, COL);//打印出棋盘的信息
    while (1)
    {
        //玩家走
        printf("玩家走\n");
        playermove(board, ROW, COL);
        Displayboard(board, ROW, COL);
        win = Isfull(board, ROW, COL);
        win=Iswin(board,ROW,COL);
        if (win != 'c')
            break;
        //电脑走
        printf("电脑走\n");
        computermove(board, ROW, COL);
        Displayboard(board, ROW, COL);
        win = Isfull(board, ROW, COL);
        win=Iswin(board,ROW,COL);
        if (win != 'c')
            break;
    }
    if (win == 'e')
        printf("平局\n");
    else if (win == '*')
        printf("玩家赢\n");
    else if (win == '#')
        printf("电脑赢\n");
}
int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        //菜单,让用户选择
        menu();
        scanf("%d", &input);
        if (input != 0)
        {
            printf("游戏开始\n");
            game();//游戏主体
 
        }
 
        else
        {
            printf("退出游戏\n");
            break;
        }
    } while (input);
 
    return 0;
}
3,最后解释
这里将两个合起来一起说。首先,在三子棋.c文件中,我们实现了上面的基本思路,而进入游戏主体部分之后,我们需要的是创建一个棋盘来存放我们的信息。之后,初始化棋盘,打印棋盘。这里,我们使用了宏定义,直接定义ROW,COL,行和列,方便我们之后进行修改,来改变棋盘的大小。而后,就是进行三子棋的玩家和电脑的走法了,玩家走比较简单,我们在打印棋盘的时候就已经让棋盘上有标坐标了,玩家只需要根据坐标来选,在将信息存入就可以了。而电脑的走法就需要我们之前使用过的rand函数了,还记得吗,不记得的话大家可以回去看看

小项目的实现:猜数字小游戏+随机数生成器的实现_C_Ryson的博客-CSDN博客

用取模的方式限制住随机数的范围,我们就可以放入棋盘了。有了这两个之后,最重要的就是判断规则了,大家有兴趣的话,可以去看看​​​​​​C语言从入门到进阶(C语言入门搞定C语言C语言视频教程C语言入门到进阶C语言教程C语言教程C语言教程C语言入门教程C语言入教程C语言C语言视频C语言教程)_哔哩哔哩_bilibili

这里的规则是我自己写的,原本是想让其普适高一些,放大棋盘之后还能使用。结果发现,三子棋放大棋盘之后,先手的一定会赢,这让我之后想写的双人对战的梦想破灭了,于是,我就将其用到了五子棋(进阶版),这里碍于时间原因,就这两天写给大家吧,这里只写一下五子棋的普通版本有兴趣的话记得点个关注,明天来看哦。

在判断规则中,我们利用放进去数组元素的特点,直接返回就行,利用数组的元素来判断是否本局已经结束,而一开始,我们用变量win储存的字母c(continue)来表示游戏继续,如果win的值被改变,就证明游戏已经结束,可以跳出循环了。再进行判断的。同时,我们要注意到,因为棋盘的大小被我们所限定,还有可能出现一个问题是平局,也就是棋盘满的情况,所以我们还需要一个Isfull函数来判断一下,一旦棋盘上所有的元素都不在有空格,又还没分出胜负,那么就是平局了。这样,一个完整的判断规则就写完了。

接下来重点说一下我自己写的上面的规则,

我们知道三子棋要赢只需要有三个棋子在一条直线上,那么这时候,我们就可以创建两个变量,使其都在行和列范围内,并然后嵌套循环i,j,改变来判断竖列的,和横列的,再将i,j,同时改变,来判断斜着的直线。

这时候,不管棋盘变得多么大,判断规则依然成立。

之后的收尾,就是像上次猜数字游戏一样让用户选择是否继续玩就可以了。

2,五子棋(初阶版)
重头戏五子棋来啦。

1,思路分析
其实,五子棋的整体思路和三子棋差不多,整体构建的代码也类似,只是将判断规则放大,将棋盘放大而已,我们边看代码边说吧。

2,代码实现
首先,依然是自己的头文件。

game.h文件
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define ROW 5
#define COL 5
void Initialboard(char board[ROW][COL], int row, int col);
void Displayboard(char board[ROW][COL], int row, int col);
void playeremove(char board[ROW][COL], int row, int col);
void computermove(char board[ROW][COL], int  row, int col);
char Iswin(char board[ROW][COL], int  row, int col);
char Isfull(char board[ROW][COL], int row, int col);
简化代码的运用,这里我们将ROW和COL定义成了5,当然,也可以自己定得更大,不过,跟电脑对战(还没升级的),太大的棋盘反而没什么用处。虽然升级也不算太好,毕竟本人才疏学浅,主要升级的思路只在于,让电脑在玩家下的棋的周围下,之后学得更多,在来进行优化吧,这里这个简陋的升级就不展示啦。

game.c文件
#define  _CRT_SECURE_NO_WARNINGS
#include"game.h"
//初始化棋盘
void Initialboard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++)
        {
            board[i][j] = ' ';
        }
    }
}
//打印棋盘
//   |   |   
//---|---|—-
//   |   |   
//---|—-|---
//   |   |   
void Displayboard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        if (i == 0)
        {
            for (j = 0; j < col; j++)
            {
                if (j == 0)
                    printf("  %d  ", j);
                else
                    printf(" %d  ", j);
            }
            printf("\n");
        }
        printf("%d", i);
        for (j = 0; j < col; j++)
        {
            printf(" %c ", board[i][j]);
            if (j < (col - 1))
            {
                printf("|");
            }
 
        }
        printf("\n");
        if (i<row - 1)
        {
            for (j = 0; j < col; j++)
            {
                if (j == 0)
                    printf(" ---");
                else
                    printf("---");
                if (j < (col - 1))
                    printf("|");
            }
        }
        printf("\n");
    }
}
//实现玩家下棋
void playermove(char board[ROW][COL], int row, int col)
{
    int i, j;
    printf("请根据图示输入要走的坐标:");
    while (1)
    {
        scanf("%d%d", &i, &j);
        if (i >= 0 && i < 5 && j >= 0 && j <5 && board[i][j] == ' ')
        {
            board[i][j] = '*';
            break;
        }
        else
            printf("输入有误,请重新输入。");
    }
}
 
void computermove(char board[ROW][COL], int  row, int col)
{
    while (1)
    {
        int i = rand() % row;
        int j = rand() % col;
        if (board[i][j] == ' ')
        {
            board[i][j] = '#';
            break;
        }
    }
}
 
char Iswin(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col - 4; j++)
        {
            if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] &&board[i][j+2]==board[i][j+3]&&board[i][j+3]==board[i][j+4]&& board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (j = 0; j < col; j++)
    {
        for (i = 0; i < row - 4; i++)
        {
            if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i + 2][j] == board[i + 3][j] && board[i + 3][j] == board[i + 4][j] && board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (i = 0, j = 0; i < row - 4 && j < col - 4; i++, j++)
    {
        if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4]&& board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    for (i = row - 1, j = 0; i >= 0 && j < col - 4; i--, j++)
    {
    
        if (board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j + 2] && board[i - 2][j + 2] == board[i - 3][j + 3] && board[i - 3][j + 3] == board[i - 4][j + 4]&& board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    return 'c';
}
char Isfull(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (board[i][j] == ' ')
                return 'c';
        }
    }
    return 'e';
 
}
五子棋(初阶).c文件
#define  _CRT_SECURE_NO_WARNINGS
#include"game.h"
//说明:
//*是玩家走的棋子
//#是电脑走的棋子
void menu()
{
    printf("*****************\n");
    printf("**1,play 0,exit**\n");
    printf("*****************\n");
    printf("请选择:");
}
void game()
{
    char win = 'c';
    char board[ROW][COL] = { 0 };//创建棋盘
    Initialboard(board, ROW, COL);//初始化棋盘
    Displayboard(board, ROW, COL);//打印出棋盘的信息
    while (1)
    {
        //玩家走
        printf("玩家走\n");
        playermove(board, ROW, COL);
        Displayboard(board, ROW, COL);
        win = Isfull(board, ROW, COL);
        win = Iswin(board, ROW, COL);
        if (win != 'c')
            break;
        //电脑走
        printf("电脑走\n");
        computermove(board, ROW, COL);
        Displayboard(board, ROW, COL);
        win = Isfull(board, ROW, COL);
        win = Iswin(board, ROW, COL);
        if (win != 'c')
            break;
    }
    if (win == 'e')
        printf("平局\n");
    else if (win == '*')
        printf("玩家赢\n");
    else if (win == '#')
        printf("电脑赢\n");
}
int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        //菜单,让用户选择
        menu();
        scanf("%d", &input);
        if (input != 0)
        {
            printf("游戏开始\n");
            game();//游戏主体
 
        }
 
        else
        {
            printf("退出游戏\n");
            break;
        }
    } while (input);
 
    return 0;
}
3,最后解读
这里,我们再次合起来说吧,大家也可以看到,实际上和三子棋的实现没有多大的区别,主要的改变,都在规则部分,我们拿出来细说。

char Iswin(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col - 4; j++)
        {
            if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] &&board[i][j+2]==board[i][j+3]&&board[i][j+3]==board[i][j+4]&& board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (j = 0; j < col; j++)
    {
        for (i = 0; i < row - 4; i++)
        {
            if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i + 2][j] == board[i + 3][j] && board[i + 3][j] == board[i + 4][j] && board[i][j] != ' ')
            {
                return board[i][j];
            }
        }
    }
    for (i = 0, j = 0; i < row - 4 && j < col - 4; i++, j++)
    {
        if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4]&& board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    for (i = row - 1, j = 0; i >= 0 && j < col - 4; i--, j++)
    {
    
        if (board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j + 2] && board[i - 2][j + 2] == board[i - 3][j + 3] && board[i - 3][j + 3] == board[i - 4][j + 4]&& board[i][j] != ' ')
        {
            return board[i][j];
        }
    }
    return 'c';
}
可以看到,我们将规则又扩大了一些,从原本的三个扩大到了5个位置的相等,而之后同样也是返回数组里的元素,来帮助判断胜负。同时要注意不要越界访问了。

这就是今天的内容了,之后五子棋的进阶部分找时间再分享给大家,进阶部分更加精彩,有我自己捣鼓的一个简陋的登录系统(只是一个雏形,不能储存数据),以及玩家对战部分等,码字不易,大家点点关注,给我点个赞吧,我会坚持更新的。如果有错,请联系修改,你们的支持是我更新的动力。

参考资料:

五子棋图片 - 国内版 Bing images

三子棋图片 - 国内版 Bing images
————————————————
版权声明:本文为CSDN博主「C_Ryson」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/C_Ryson/article/details/120961956

...全文
27 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
小笼包95 2021-12-01
  • 打赏
  • 举报
回复

64,192

社区成员

发帖
与我相关
我的任务
社区描述
学习「 算法 」的捷径就是 「 题海战略 」,社区由「 夜深人静写算法 」作者创建,三年ACM经验,校集训队队长,亚洲区域赛金牌,世界总决赛选手。社区提供系统的训练,答疑解惑,面试经验,大厂内推等机会
社区管理员
  • 英雄哪里出来
  • 芝麻粒儿
  • Amy卜bo皮
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

QQ群:480072171

英雄算法交流 8 群

 

试试用AI创作助手写篇文章吧