#初学者必看#手把手教你写三子棋教程#B站鹏哥

前言

会写的不一定真的懂了,本篇文章结合了B站鹏哥的写作手法,循序渐进推进知识点,一步步教你写代码,非常适合初学者学习,建议反复观看。

同时作者我也是一个C语言B站初学者,欢迎一起学习交流,批评指正。


让我们先写一个大纲,告诉你的电脑要做什么?


告诉你的电脑它要做什么,也就是给它安排任务,然后指导它完成这个任务。

我们先说一个具体流程:

第一部分:

ccd8c58428eb40579bc365f2fe199717.png

第二部分: 

 3970f8f344c140baa9f1f925456050a7.png

 以上附上整个程序的流程图,这也就是你要让电脑完成的任务。当你知道你将要做什么就好办了,接下来就可以和电脑谈谈具体的细节了。

让我们再谈谈具体细节,程序是怎么运行的?


第一部分:

创建main()函数,打印你的菜单,并使你的菜单有效。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
	printf("**************************************************\n");
	printf("****************     三子棋      *****************\n");
	printf("************* 1.游戏开始 2.游戏结束 **************\n");
	printf("**************************************************\n");
}
void   game()
{
  //第二部分实现
}
int main()
{
	//打印菜单
	menu();  
	int input;
	do {
		printf("请输入1/0是否开始游戏->\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("您的三子棋游戏开始\n");
            game();
			break;
		case 0:
			printf("谢谢!游戏已经退出\n ");
			break;
		default:
			printf("对不起,请输入正确的值\n");
			break;
		}
	} while (input);
    return 0;
}

重点!!!告诉大家我踩过的坑及解决方案:

1.你的printf和scanf可能会因为你个人的习惯将他们放在do{}while循环的外面,这会导致后面break无法使用。

2.你也许考虑到用if()else if来写但在写if()else of 时一定不要忘了else 。

3.有些人可能不采用1或0的菜单键,而是采用像yes/no的字符串键,这样就不能用switch case 的分支了,这时要才用if, else if分支,并且在使用它时不能用“==”来判断,而是用trcmp(arr,"yes")==0来实现。

4.我用的是VS2022的编译器,我用了#define _CRT_SECURE_NO_WARNINGS,及#include<stdio.h>,也会报一个scanf返回值被忽略的警告。(有大神知道是什么回事吗?)

加#include <cstdlib>头文件就好了

注:这里引用了一个自定义#include"game.h"的头文件,后面会用到,用来声明函数。

看看结果吧:

036e9d1cea484d5a8794f8f3bced482d.png


 第二部分:(重点)

4952d823970f42d7990df90c843132c6.png

接下来所有需要创建的第二部分函数都在void game()函数中。

我们有了菜单,就可以开始下棋了,但是我们现在还没有棋盘,所以准备一个棋盘吧。

初始化棋盘 及 打印棋盘

void game()
{
	//创建一个二维数组
	char shangziqi[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(shangziqi, ROW, COL);
	//打印棋盘
	DipiayBoard(shangziqi, ROW, COL);
}
//头文件中声明函数
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char shangziqi[ROW][COL], int row, int col);
//打印棋盘
void DipiayBoard(char shangziqi[ROW][COL], int row, int col);

程序中另建函数文件,增加可读性

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include<stdio.h>
//初始化棋盘
void InitBoard(char shangziqi[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++) {
            shangziqi[i][j] = ' ';
        }
    }
}
//打印棋盘
void DipiayBoard(char shangziqi[ROW][COL], int row, int col)
{
    int i, j;
    for (i = 0; i < row; i++) 
    {
        for (j = 0; j < col; j++) 
        {
            printf(" %c ", shangziqi[i][j]);
            if (j < col - 1)
            {
                printf("|");
            }
        }
        printf("\n");
        if (i < row - 1)
        {
            for (j = 0; j < row; j++) 
            {
                printf("---");
                if (j < col - 1)
                {
                    printf("|");
                }
            } 
            printf("\n");
        }
    }
}

这样就把棋盘创建出来了,并可以打印出来了。

这里的打印方法建议采用内存分析法分析,因为打印方法描述篇幅太大,这里不便描述,有兴趣的Q我吧。

看看效果吧:

6f72c50283d549eb8983b51200c06fb2.png


 玩家下 

先在game函数中创建函数名

//玩家下
	PlayGo(shangziqi, ROW, COL);
//然后打印
	DipiayBoard(shangziqi, ROW, COL);

然后在自定义头文件中声明

//玩家下
void PlayGo(char shangziqi[ROW][COL], int row, int col);

最后写PayGo()函数的具体实现方法

}//玩家下
void PlayGo(char shangziqi[ROW][COL], int row, int col)
{
    int arr1, arr2;
    printf("到你走了\n");
    printf("操作介绍:输入1.1至3.3之内的坐标\n");
    while (1) {
        printf("请输入坐标—>\n");
        scanf("%d%d", &arr1, &arr2);
        if (arr1 >= 1 && arr1 <= row && arr2 <= col && arr2 >= 1)
        {
            if (shangziqi[arr1 - 1][arr2 - 1] == ' ') {
                shangziqi[arr1 - 1][arr2 - 1] = '*';
                break;
            }
            else {
                printf("该位置已被占用\n");
            }
        }
        else
        {
            printf("您的输入范围有误,请重新输入->\n");
        }
    }
}

细节解读:

1.为什么while()循环条件是1?

还记得我们最后一部分是判断输赢吗,在没有判断输赢前是要一直下的,所以何时跳过循环是在最后判断输赢的时候实现的。写到这,确实是一个死循环,但是还没写完,写完时就可以挑出死循环了。

2.这里的两个if分别是什么意思?

第一个if是判断玩家输入的的坐标是否在1到3之间,第二个if是判断说下的棋盘格子是否落子了。

注:输入坐标时两个数子字间不得加,。

看看效果:

2985640b03f947d1953573fde138da0b.png


电脑下

人和ai之间的博弈开始了

先在game函数中创建函数名

//ai下
	PlayGoai(shangziqi, ROW, COL);
	//下完打印棋盘
	DipiayBoard(shangziqi, ROW, COL);

然后在自定义头文件中声明

//ai下
void PlayGoai(char shangziqi[ROW][COL], int row, int col);

最后写PlayGoai()函数的具体实现方法

#include<time.h>
#include <cstdlib>
//ai下
void PlayGoai(char shangziqi[ROW][COL], int row, int col)
{
    while (1) {
        srand((unsigned int)time(NULL));
        int arr3 = rand() % row;
        int arr4 = rand() % col;
        if (shangziqi[arr3][arr4] == ' ')
        {
            shangziqi[arr3][arr4] = '#';
            break;
        }
    }
}

细节解析:

rand是生成随机1-1024数字的库函数,这里将它% row或% col,是将它的随机值控制在1-3之间,同时为了保证它在每次启动程序的时候随机值都不一样,他会配合srand函数一起使用,如上述使用方法,因为是库函数要引用头文件,这里是#include<time.h>和#include <cstdlib>。

看看结果:
519ae750cdeb439f85b4eba906f5291c.png


判断输赢(警告:写完这个函数还没完,还有最后一步下面讲)

这里讲一个适合初学者学习的判断函数

先在game函数中创建函数名

void game()
{
	//创建一个二维数组
	char shangziqi[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(shangziqi, ROW, COL);
	//打印棋盘
	DipiayBoard(shangziqi, ROW, COL);
	//玩家下
	PlayGo(shangziqi, ROW, COL);
    //下完打印棋盘
	DipiayBoard(shangziqi, ROW, COL);
//第一部分
char ret = IsWin(shangziqi, ROW, COL);

	//ai下
	PlayGoai(shangziqi, ROW, COL);
	//下完打印棋盘
	DipiayBoard(shangziqi, ROW, COL);
//第二部分
	ret = IsWin(shangziqi, ROW, COL);

//第三部分
	if (ret == '*')
	{
		printf("玩家赢\n");
		//break;
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
		//break;
	}
	else if (ret == 'q')
	{
		printf("平局\n");
		//break;
	}
}

细节分析:

这里有三个部分,我们一个个来讲,首先,第一部分创建了一个char 型的变量,名字是ret,用来返回一个值,它会用于第三部分的if判断。然后,第二部分也是使用了这个char型的ret变量,它和第一部分的作用是一样的,都是返回一个值,这个值是对人或ai下完后的一个输赢的判断,当ret 是#时电脑赢,当ret是*时是玩家赢,是q时是平局。

在自定义头文件中声明

//判断输赢
char IsWin(char shangziqi[ROW][COL], int row, int col);

最后写IsWin()函数的具体实现方法

别看它很多,原理很简单的,没有那个是我们没见过的,坚持住!!!

int IsFin(char shangziqi[ROW][COL], int row, int col)
{
    int i, j;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (shangziqi[i][j] == ' ')
            {
                return 0;
            }
        }
    }
    return 1;
}
char IsWin(char shangziqi[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        if (shangziqi[i][0] == shangziqi[i][1] && shangziqi[i][2] == shangziqi[i][1] && shangziqi[i][0] != ' ')
        {
            return shangziqi[i][1];
        }
    }
    for (j = 0; j < col; j++)
    {
        if (shangziqi[0][j] == shangziqi[1][j] && shangziqi[1][j] == shangziqi[2][j] && shangziqi[0][j] != ' ')
        {
            return shangziqi[1][j];
        }
    }
    if (shangziqi[0][0] == shangziqi[1][1] && shangziqi[1][1] == shangziqi[2][2] && shangziqi[1][1] != ' ')
    {
        return  shangziqi[1][1];
    }
    if (shangziqi[2][0] == shangziqi[1][1] && shangziqi[0][2] == shangziqi[1][1] && shangziqi[1][1] != ' ')
    {
        return  shangziqi[1][1];
    }
    if (1 == IsFin(shangziqi, ROW, COL))
    {
        return 'q';
    }
    return 'c';
}

细节分析:

让我们看看他是如何返回一个值的吧!

 这里的if判断条件其实就将它所有的结果都包括进来了,要么是束三连,要么是横三连,要么是二斜连,就这八种情况,判断连起来的是*还是#就可以判断哪个输赢; 还有一种结果就是平局,这时候就用除上面结果外的else判断就可以了。

而上面的InFin函数的作用是判断什么时候下完了的函数,也就是什么时候第一次出现同三连的情况。

当写到这里,你让电脑做的事情基本上都讲完了,但还差一步.....

最后一步

你的电脑知道了怎么下棋的流程,但是你应该知道下棋是你一步我一步循环走的,而现在电脑只会走一次,你必须让它循环起来,直到下完为止,所有我们还需要一个while循环。

void game()
{
	//创建一个二维数组
	char shangziqi[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(shangziqi, ROW, COL);
	//打印棋盘
		DipiayBoard(shangziqi, ROW, COL);
//循环开始
		while (1) {
	//玩家下
		PlayGo(shangziqi, ROW, COL);
		DipiayBoard(shangziqi, ROW, COL);
		char ret = IsWin(shangziqi, ROW, COL);
		//ai下
		PlayGoai(shangziqi, ROW, COL);
		//下完打印棋盘
		DipiayBoard(shangziqi, ROW, COL);
		ret = IsWin(shangziqi, ROW, COL);
		if (ret == '*')
		{
			printf("玩家赢\n");
			break;
		}
		else if (ret == '#')
		{
			printf("电脑赢\n");
			break;
		}
		else if (ret == 'q')
		{
			printf("平局\n");
			break;
		}
	}//循环结束
}

到目前为止整个程序已经完成,解释一下:while(1)是一种偷懒的写法,这里的break就是跳出循环的关键。

看看结果吧:

 真棒!!!


求家人们给个三连吧,我会持续发布一些适合初学者看的文章,让大家少走弯路,避免我踩过的坑,求求了!

猜你喜欢

转载自blog.csdn.net/2301_77479336/article/details/129994263