会写的不一定真的懂了,本篇文章结合了B站鹏哥的写作手法,循序渐进推进知识点,一步步教你写代码,非常适合初学者学习,建议反复观看。
同时作者我也是一个C语言B站初学者,欢迎一起学习交流,批评指正。
告诉你的电脑它要做什么,也就是给它安排任务,然后指导它完成这个任务。
我们先说一个具体流程:
第一部分:
第二部分:
以上附上整个程序的流程图,这也就是你要让电脑完成的任务。当你知道你将要做什么就好办了,接下来就可以和电脑谈谈具体的细节了。
创建main()函数,打印你的菜单,并使你的菜单有效。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#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
加#include
注:这里引用了一个自定义#include"game.h"的头文件,后面会用到,用来声明函数。
看看结果吧:
接下来所有需要创建的第二部分函数都在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
//初始化棋盘
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我吧。
看看效果吧:
先在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是判断说下的棋盘格子是否落子了。
注:输入坐标时两个数子字间不得加,。
看看效果:
电脑下
人和ai之间的博弈开始了
先在game函数中创建函数名
//ai下
PlayGoai(shangziqi, ROW, COL);
//下完打印棋盘
DipiayBoard(shangziqi, ROW, COL);
然后在自定义头文件中声明
//ai下
void PlayGoai(char shangziqi[ROW][COL], int row, int col);
最后写PlayGoai()函数的具体实现方法
#include
#include
//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
这里讲一个适合初学者学习的判断函数
先在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就是跳出循环的关键。
看看结果吧:
真棒!!!
求家人们给个三连吧,我会持续发布一些适合初学者看的文章,让大家少走弯路,避免我踩过的坑,求求了!