基本逻辑:我用模块化编程,文件分为
测试文件:test.c
游戏实现文件:game.h 和 game.c
测试文件里,我会写出游戏的整个逻辑。而游戏实现文件里,我会写出游戏具体是怎样运行的。
void menu()
{
printf("**********************\n");
printf("******* 1.play ******\n");
printf("******* 0.exit ******\n");
printf("**********************\n");
printf("请选择:");
}
void test()
{
int input = 0;
do
{
menu();//打印菜单
scanf("%d", &input);
switch (input)
{
case 1: printf("开始游戏:>\n");
game();
break;
case 0: printf("结束游戏:>\n");
break;
}
}while (input);
}
然后,我们开始写game()函数
三子棋,无非就是一个3 X 3的表格,说到表格,我们自然而然会想到二维数组。
没错,我们可以定义一个二维数组,然后我们人和电脑在这个二维数组里面下棋。
//用宏定义棋盘大小,可以方便以后改棋盘大小
//但是这里我就只演示三子棋,如有兴趣自行研究
#define ROW 3
#define COL 3
char board[ROW][COL];//定义数组
//把数组传入进行初始化,初始化为全空格
void Init_Board(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] = ' ';
}
}
}
数组有了,我们还需要棋盘,这样可以让程序更好看。
| |
---|---|---
| |
---|---|---
| |
这个棋盘怎么打印
我们不妨把棋盘看成2排字符,用三次,并且把多余的部分去掉
第一部分,如图我们打印3个空格再打印一个竖杠,如此打印3次是不是就有了第一排的雏形,再把最后次打印的竖杠去掉,就完美了。当然我们会在两个空格的中间打印字符,以达到下棋的目的,所以中间并不是空格而是%c。
第二部分,打印3个横线再来个竖杠,和第一部分同样,如此打印3次是不是就有了第二排的雏形,再把最后次打印的竖杠去掉,就完美了。
void Print_Board(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
写到这来捋一下
void game(void)
{
char board[ROW][COL];//定义数组
Init_Board(board, ROW, COL);//初始化数组全为空格
Print_Board(board, ROW, COL);//打印棋盘
while (1)//开始下棋
{
}
}
游戏不是下一次就完了,所以我们采用循环。
接下来,我们写玩家和电脑怎样下棋
下棋,就是往二维数组中输入一个字符再把它打印到屏幕上就好了。
但是我们还是要考虑一些问题,比如万一玩家不明白代码的底层逻辑:数组是从0开始的,但是我们日常生活中行和列都是从1开始的。
还有玩家输入的位置超出数组的范围了,输入的位置已经有棋子了等,这些都是我们作为游戏设计者要想到的。
void Player_Move(char board[ROW][COL], int row, int col)
{
while (1)
{
printf("玩家下棋->");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
if (x <= row && x > 0 && y <= col && y > 0)//是否在数组范围内
{
//将常识输入转换为数组的下标
x = x - 1;
y = y - 1;
if (board[x][y] == ' ')//是否有重复输入
{
board[x][y] = '*';
break;
}
else
{
printf("输入错误,请重新输入\n");
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
}
比起玩家下棋,电脑下棋容易得多,我们只需要生成随机值,再将随机值作为数组的下标输入就行。当然我们还是要考虑输入重复问题。
void Computer_Move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
//生成随机数,并且模上row,col就能得到我们想要的下标。
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
else
{
;
}
}
}
玩家电脑下完棋了,我们还需要对输赢进行判断。
在这分为4中情况
'#'为电脑赢
'*'为玩家赢
'P'为平局
'C'为没分出胜负,继续游戏
接下来是重头戏,也是这个程序最巧妙的地方
我们都知道三子棋,只要有3个棋子相同,就能获胜
但是程序是怎么知道是玩家打印的字符还是电脑打印的呢?
玩家输入,打印 '*' 。电脑输入,打印 '#' 。
进行比较,如果有三个字符相同且不是空格的话,Is_Win函数返回 '*' 或 '#' 来进行判断是玩家打印的字符相同还是电脑打印的字符相同。
如果棋盘满了,那就是平局Is_Win函数返回 'P' 。
如果以上3种情况都不满足则Is_Win函数返回 'C' 。
//static修饰,让Is_Full函数只能在game.c文件中使用。
//Is_Full函数是Is_Win函数的一部分,用于判断是否平局。
static int Is_Full(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char Is_Win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断每行是否相等
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]
&& board[i][0] != ' ')
{
return board[i][0];
}
}
//判断每排是否相等
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i]
&& board[0][i] != ' ')
{
return board[0][i];
}
}
//判断对角线是否相等
if (board[0][0] == board[1][1] && board[1][1] == board[2][2]
&& board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0]
&& board[1][1] != ' ')
{
return board[1][1];
}
//判断是否平局
if (Is_Full(board, row, col) == 1)
{
return 'P';
}
//都不是返回'C'继续游戏
return 'C';
}
void game(void)
{
char ret = 0;
char board[ROW][COL];//定义数组
Init_Board(board, ROW, COL);//初始化数组全为空格
Print_Board(board, ROW, COL);//打印棋盘
while (1)//开始下棋
{
Player_Move(board, ROW, COL);
Print_Board(board, ROW, COL);
ret = Is_Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
Computer_Move(board, ROW, COL);
Print_Board(board, ROW, COL);
ret = Is_Win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '#')
printf("电脑赢了\n");
else if (ret == '*')
printf("玩家赢了\n");
else if (ret == 'P')
printf("平局\n");
}
#pragma once
#define ROW 3
#define COL 3
void Init_Board(char board[ROW][COL], int row, int col);
void Print_Board(char board[ROW][COL], int row, int col);
void Player_Move(char board[ROW][COL], int row, int col);
void Computer_Move(char board[ROW][COL], int row, int col);
char Is_Win(char board[ROW][COL], int row, int col);
看到这,三子棋逻辑你看懂了嘛?
希望这篇小博客能帮到你。