文章前言:
本篇文章主要是介绍简单三子棋的编写。
通过本文章,我希望入门读者可以明白一段程序的编写,其逻辑是通过一个个函数分开且高效地耦合所实现的。这个是我认为程序员想要顺利编写程序时必须要完成的东西。
整体的框架:
对于三子棋的编写,我使用三个文件来完成:
1、san_borad.c 该文件中放的是程序的主体框架
2、game.h 这里包含的是自定义函数的声明以及宏定义和其它宏文件,其它文件需要包含它。
3、game.c 这里包含的是自定义函数的具体实现
void menu()
{
printf("*************************************\n");
printf("************ 1、play *************\n");
printf("************ 0、exit *************\n");
printf("*************************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("已进入游戏:\n");
game();
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入非法\n");
}
} while (1);
}
棋盘的样式及步骤分析:
我想象棋盘是这样的:
步骤分析:
1、最开始数组里面都是空格(初始化棋盘)
2、显示数组内的元素(棋盘的打印)
3、定义宏,以便实现X子棋
4、开始下棋(还要判断棋盘是否下满)
5、判断输赢
定义宏,以便实现X子棋:
//在game.h中定义宏
#define ROW 3
#define COL 3
显示数组内的元素(棋盘的打印):
这里存在一个比较难的点:
如果想要实现X子棋,棋盘的打印必须不能写死,要借助循环来灵活化。
思路如下:
1、将棋盘分为数据行和分割行
2、在数组的最后不需要分割行,所以在最后一次循环不需要打印分割行
3、每一行都只需打印 COL - 1 个 |
//打印棋盘
void Print(char arr[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", arr[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
printf("___");//这里就是三个下划线为一组
if (k < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
下棋:
接下来到了下棋。
按照道理来说,在每一次下棋之前都需要先判断这一局有没有结束,但这里函数实现我想默认其可以将该局游戏进行下去。
下棋的主体无非两个:玩家以及电脑(这里不是玩家VS玩家)
总体上,在下每一步棋都要判断该处没有下过棋才能下。
玩家:棋盘的坐标默认是(1,1)而数组默认为(0,0),这个要注意,*表示玩家。
电脑:使用随机数来确认坐标,#表示电脑。
下面是具体实现:
//玩家下棋
void player(char arr[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int flag = 1;
do
{
printf("请输入坐标:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = '*';
flag = 0;
}
else
{
printf("该处已下过\n");
}
}
} while (flag);
}
//电脑下棋
void comper(char arr[ROW][COL], int row, int col)
{
while (true)
{
int x = rand() % row;
int y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
主体部分:
这里的主体不是最终版本,还需要改进,那就是引入对棋局的判断
void test()
{
srand((unsigned int)time(NULL));
char arr[ROW][COL] = { 0 };
init(arr, ROW, COL);
do
{
printf("请玩家下棋:\n");
player(arr, ROW, COL);
printf("电脑下棋:\n");
comper(arr, ROW, COL);
Print(arr, ROW, COL);
} while (1);
}
判断棋局是否进行下去:
在每一步棋下完后,棋局下面的走向一共有四种:
1、继续下去
2、玩家赢
3、电脑赢
4、平局
对于此,我用1表示玩家赢,2表示电脑赢,3表示继续,0表示平局。
具体实现:
//判断谁赢
int judge(char arr[ROW][COL], int row, int col)
{
int num = -1;
char sign = ' ';
//行
for (int i = 0; i < row; i++)
{
sign = arr[i][0];
for (int j = 0; j < col; j++)
{
if (arr[i][j] == ' ' || arr[i][j] != sign)
{
break;
}
if (j == col - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
}
for (int i = 0; i < col; i++)
{
sign = arr[0][i];
for (int j = 0; j < row; j++)
{
if (arr[j][i] == ' ' || arr[j][i] != sign)
{
break;
}
if (j == row - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
}
//正对角线
for (int i = 0; i < row; i++)
{
sign = arr[0][0];
if (arr[i][i] == ' ' || sign != arr[i][i])
{
break;
}
if (i == row - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
//副对角线
sign = arr[row - 1][0];
int k = 0;
for (int i = row - 1; i >= 0; i--)
{
if (arr[i][k] == ' ' || arr[i][k] != sign)
{
break;
}
k--;
if (i == 0)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
//平局
int flag = 1;
for (int i = 0; i < row && flag == 1; i++)
{
for (int j = 0; j < col; j++)
{
if (arr[i][j] == ' ')
{
flag = 0;
break;
}
}
}
if (flag == 1)
{
return 0;
}
//什么都不是,那就继续
return 3;
}
至此,可以说已经完成了三子棋的创建了,下面是主体部分:
void test()
{
srand((unsigned int)time(NULL));
char arr[ROW][COL] = { 0 };
init(arr, ROW, COL);
while(true)
{
int judgement = -1;
printf("请玩家下棋:\n");
player(arr, ROW, COL);
judgement = judge(arr, ROW, COL);
Print(arr, ROW, COL);
if (judgement == 0)
{
printf("平局\n");
break;
}
else if (judgement == 1)
{
printf("玩家赢\n");
break;
}
else if(judgement == 2)
{
printf("电脑赢\n");
break;
}
printf("电脑下棋:\n");
comper(arr, ROW, COL);
judgement = judge(arr, ROW, COL);
Print(arr, ROW, COL);
if (judgement == 0)
{
printf("平局\n");
break;
}
else if (judgement == 1)
{
printf("玩家赢\n");
break;
}
else if (judgement == 2)
{
printf("电脑赢\n");
break;
}
}
}
全部整合:
//game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//在game.h中定义宏
#define ROW 3
#define COL 3
void init(char arr[ROW][COL], int row, int col);
void Print(char arr[ROW][COL], int row, int col);
void player(char arr[ROW][COL], int row, int col);
void comper(char arr[ROW][COL], int row, int col);
int judge(char arr[ROW][COL], int row, int col);
//game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化数组都为空格
void init(char arr[ROW][COL], int row, int col)
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
arr[i][j] = ' ';
}
}
}
//打印棋盘
void Print(char arr[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", arr[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (int k = 0; k < col; k++)
{
printf("___");
if (k < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
//玩家下棋
void player(char arr[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int flag = 1;
do
{
printf("请输入坐标:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = '*';
flag = 0;
}
else
{
printf("该处已下过\n");
}
}
} while (flag);
}
//电脑下棋
void comper(char arr[ROW][COL], int row, int col)
{
while (true)
{
int x = rand() % row;
int y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
//判断谁赢
int judge(char arr[ROW][COL], int row, int col)
{
int num = -1;
char sign = ' ';
//行
for (int i = 0; i < row; i++)
{
sign = arr[i][0];
for (int j = 0; j < col; j++)
{
if (arr[i][j] == ' ' || arr[i][j] != sign)
{
break;
}
if (j == col - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
}
//列
for (int i = 0; i < col; i++)
{
sign = arr[0][i];
for (int j = 0; j < row; j++)
{
if (arr[j][i] == ' ' || arr[j][i] != sign)
{
break;
}
if (j == row - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
}
//正对角线
for (int i = 0; i < row; i++)
{
sign = arr[0][0];
if (arr[i][i] == ' ' || sign != arr[i][i])
{
break;
}
if (i == row - 1)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
//副对角线
sign = arr[row - 1][0];
int k = 0;
for (int i = row - 1; i >= 0; i--)
{
if (arr[i][k] == ' ' || arr[i][k] != sign)
{
break;
}
k--;
if (i == 0)
{
if (sign == '*')
{
return 1;
}
else if (sign == '#')
{
return 2;
}
}
}
//平局
int flag = 1;
for (int i = 0; i < row && flag == 1; i++)
{
for (int j = 0; j < col; j++)
{
if (arr[i][j] == ' ')
{
flag = 0;
break;
}
}
}
if (flag == 1)
{
return 0;
}
//什么都不是,那就继续
return 3;
}
//san_borad.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("*************************************\n");
printf("************ 1、play *************\n");
printf("************ 0、exit *************\n");
printf("*************************************\n");
}
void test()
{
srand((unsigned int)time(NULL));
char arr[ROW][COL] = { 0 };
init(arr, ROW, COL);
while(true)
{
int judgement = -1;
printf("请玩家下棋:\n");
player(arr, ROW, COL);
judgement = judge(arr, ROW, COL);
Print(arr, ROW, COL);
if (judgement == 0)
{
printf("平局\n");
break;
}
else if (judgement == 1)
{
printf("玩家赢\n");
break;
}
else if(judgement == 2)
{
printf("电脑赢\n");
break;
}
printf("电脑下棋:\n");
comper(arr, ROW, COL);
judgement = judge(arr, ROW, COL);
Print(arr, ROW, COL);
if (judgement == 0)
{
printf("平局\n");
break;
}
else if (judgement == 1)
{
printf("玩家赢\n");
break;
}
else if (judgement == 2)
{
printf("电脑赢\n");
break;
}
}
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("已进入游戏:\n");
test();
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入非法\n");
}
} while (input);
return 0;
}
结语:
通过一块块函数将功能逐步实现是完成一段程序的重要思想。这里不只是三子棋,将宏改一下数值就可以实现不同的棋。