C语言初阶习题【19】三子棋游戏
1.实现三子棋游戏
2.思路
我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中
main函数在test.c中。
2.1 test.c中
- 先写main 函数,在main函数中调用test函数。
int main()
{
test();
return 0;
}
- test.c函数实现让玩家进行选择是否要进行游戏
这里用到了do…while语句,先上来打印一个菜单,让玩家进行输入,根据玩家输入进入不同的分支。
void test()
{
int input = 0;
do
{
manu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("您已退出游戏,欢迎下次再来!\n");
break;
default:
printf("您的选择有误,请重新输入:\n");
}
} while (input);
}
- manu()函数很简单,直接print打印即可。和我们之前的猜数字游戏是一样的思路
void manu(void)
{
printf("=====================\n");
printf("=====1:开始游戏=====\n");
printf("=====0:退出游戏=====\n");
printf("=====================\n");
}
这里写完,可以把game()函数先屏蔽掉看看效果,输入其他数值直接报错让玩家继续输,输入1直接break,循环继续,输入0就直接退出了。
2.2 game()的实现
game()函数实现这部分是游戏流程。game()也是放在test.c中。但是涉及到game函数具体实现都会放到game.c中去。
我们先表示棋盘:创建一个 3*3的二维数组,每个元素是一个char类型,'X’表示玩家1、'O’表示玩家2、'空格’表示空白。 我在game.c函数实现中设计了如果是和局的话用‘h’表示
因为只要游戏没有结束,就要一直下棋,所以要用到循环while
- 游戏流程:
(1)创建棋盘,并初始化~把所有位置都设为空格
(2)打印棋盘
while(1)
{
(3)玩家进行落子,让玩家来输入一组坐标(row,col),进行落子
(4)进行判定,有任何一方获胜或者平局就break;
(5)电脑进行落子~ 电脑随机落子
(6)进行判定,有任何一方获胜或者平局就break;
}
(7)判定是哪一方获胜或者平局了 - 代码实现
void game()
{
//0.创建棋盘
char chessBoard[ROW_MAX][COL_MAX] = { 0 };
//1.初始化棋盘
init(chessBoard, ROW_MAX, COL_MAX);
//2.打印棋盘
print(chessBoard, ROW_MAX, COL_MAX);
char ret = ' ';//这个需要定义在while之外
while (1)
{
//3.玩家下棋
palyer(chessBoard, ROW_MAX, COL_MAX);
print(chessBoard, ROW_MAX, COL_MAX);
ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
if ( ret!= ' ')
{
break;
}
//4.电脑下棋
computer(chessBoard, ROW_MAX, COL_MAX);
print(chessBoard, ROW_MAX, COL_MAX);
ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
if (ret != ' ')
{
break;
}
}
if (ret == 'X')
{
printf("玩家获胜\n");
}else if (ret== 'O')
{
printf("电脑获胜\n");
}
else if(ret== 'h')
{
printf("平局\n");
}
}
2.3 game.c函数实现
我们注意game.c和game.h是配套使用的,game.c中的函数需要在game.h中进行声明。
在.c文件中需要引入我们自己写的.h头文件,用的是“ ”,一般引用库函数用的< >
#include "game.h"
2.3.1 棋盘初始化
init(chessBoard, ROW_MAX, COL_MAX);
最简单的写法就是使用for循环直接遍历,给每个元素初始化为空格,后面有学到了用memset函数,直接初始化。
memset函数的头文件是<string.h> 。这个的使用可以自己搜下,比较简单有三个参数,第一个是要初始化的元素地址,我们这里就是数组首元素,第二个参数是要初始化的值,我们这里是空格,第三个就是要初始化的长度,
//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
#if 0
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
chessBoard[row][col] = ' ';
}
}
#endif
memset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}
2.3.2 棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
思路:这个地方要考虑到打印我们的棋盘,否则全是空格就看不到任何输出。
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
for (int row = 0; row < ROW_MAX; row++)
{
printf("+---+---+---+\n");
printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);
}
printf("+---+---+---+\n");
}
2.3.2 玩家下棋
- void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
- 思路:只要位置不为空就可以下棋,要注意限制玩家输入范围。
- 代码实现
//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入要下棋的坐标:x y\n");
scanf("%d %d", &x, &y);
if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX)
{
printf("您的输入坐标有误请重新输入:\n");
continue;
}
if (chessBoard[x][y] != ' ')
{
printf("您下的位置已经有棋子了。请重新输入:\n");
continue;
}
else
{
chessBoard[x][y] = 'X';
break;
}
}
}
2.3.3 电脑下棋
- void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
- 思路:电脑需要使用rand()函数生成随机数进行下棋,注意两个点,其一要限制输入0 1 2不能超过3,其二需要配合srand()函数一起使用,srand()需要用到时间戳time()函数,我们这个只需要调用一次放在了test函数中。这个在猜数字游戏里面也有实现过。rand函数的头文件是<stdlib.h> time函数的头文件是<time.h>
- 代码实现
void test()
{
int input = 0;
srand((unsigned int)time(NULL)); //在循环外面
do
{
manu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch(input)
{
case 1:
//game();
break;
case 0:
printf("您已退出游戏,欢迎下次再来!\n");
break;
default:
printf("您的选择有误,请重新输入:\n");
}
} while (input);
}
//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
printf("电脑下棋:\n");
while (1)
{
int a = rand() % ROW_MAX;
int b = rand() % COL_MAX;
if (chessBoard[a][b] != ' ')
{
continue;
}
chessBoard[a][b] = 'O';
break;
}
}
2.3.4 判断输赢
-
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
-
思路:这里之所以是char类型的返回值,是为了能够方便我们进行判断是谁赢了。判断的思路很简单,判断三行是否一致,三列是否一致,对角线是否一致,棋盘是否下满为和局,这里涉及到一个棋盘是否满的函数,这个函数我们只需要我们的game.c中使用,所以给添加了static,关闭它的外部属性,其他.c文件都不能调用我们这个函数。
-
代码实现
static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{
int i = 0;
int j = 0;
for (i = 0; i < ROW_MAX; i++)
{
for (j = 0; j < COL_MAX; j++)
{
if (chessBoard[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
//判断三行
int i = 0;
for (i = 0; i < row; i++)
{
if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]
&& chessBoard[i][0] != ' ')
{
return chessBoard[i][0];
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]
&& chessBoard[0][i] != ' ')
{
return chessBoard[0][i];
}
}
//判断对角线
if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]
&& chessBoard[0][0] != ' ')
{
return chessBoard[0][0];
}
if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]
&& chessBoard[0][2] != ' ')
{
return chessBoard[0][2];
}
if (is_Full(chessBoard))
{
return 'h';//和局
}
return ' ';//游戏继续
}
我在写这部分的时候各种出错,有时候是少了一个等号,有时候是用错了循环变量,调试真的很重要,当发现自己的错误的时候有时候真的哭笑不得,还好有调试功能,可以让我一步一步跟着代码走排查自己的问题。
3.代码实现
- test.c
#include "game.h"
void manu(void)
{
printf("=====================\n");
printf("=====1:开始游戏=====\n");
printf("=====0:退出游戏=====\n");
printf("=====================\n");
}
void game()
{
//0.创建棋盘
char chessBoard[ROW_MAX][COL_MAX] = { 0 };
//1.初始化棋盘
init(chessBoard, ROW_MAX, COL_MAX);
//2.打印棋盘
print(chessBoard, ROW_MAX, COL_MAX);
char ret = ' ';
while (1)
{
//3.玩家下棋
palyer(chessBoard, ROW_MAX, COL_MAX);
print(chessBoard, ROW_MAX, COL_MAX);
ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
if ( ret!= ' ')
{
break;
}
//4.电脑下棋
computer(chessBoard, ROW_MAX, COL_MAX);
print(chessBoard, ROW_MAX, COL_MAX);
ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
if (ret != ' ')
{
break;
}
}
if (ret == 'X')
{
printf("玩家获胜\n");
}else if (ret== 'O')
{
printf("电脑获胜\n");
}
else if(ret== 'h')
{
printf("平局\n");
}
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
manu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("您已退出游戏,欢迎下次再来!\n");
break;
default:
printf("您的选择有误,请重新输入:\n");
}
} while (input);
}
int main()
{
test();
}
- game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define ROW_MAX 3
#define COL_MAX 3
//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX],int row,int col );
//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col);
//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col);
//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col);
//判断输赢
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col);
- game.c
#include "game.h"
//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
memset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}
//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
for (int row = 0; row < ROW_MAX; row++)
{
printf("+---+---+---+\n");
printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);
}
printf("+---+---+---+\n");
}
//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入要下棋的坐标:x y\n");
scanf("%d %d", &x, &y);
if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX)
{
printf("您的输入坐标有误请重新输入:\n");
continue;
}
if (chessBoard[x][y] != ' ')
{
printf("您下的位置已经有棋子了。请重新输入:\n");
continue;
}
else
{
chessBoard[x][y] = 'X';
break;
}
}
}
//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
printf("电脑下棋:\n");
while (1)
{
int a = rand() % ROW_MAX;
int b = rand() % COL_MAX;
if (chessBoard[a][b] != ' ')
{
continue;
}
chessBoard[a][b] = 'O';
break;
}
}
static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{
int i = 0;
int j = 0;
for (i = 0; i < ROW_MAX; i++)
{
for (j = 0; j < COL_MAX; j++)
{
if (chessBoard[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断输赢
//返回X表示玩家获胜
//返回O表示电脑获胜
//返回h表示和局
//返回j表示游戏继续
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
{
//判断三行
int i = 0;
for (i = 0; i < row; i++)
{
if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]
&& chessBoard[i][0] != ' ')
{
return chessBoard[i][0];
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]
&& chessBoard[0][i] != ' ')
{
return chessBoard[0][i];
}
}
//判断对角线
if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]
&& chessBoard[0][0] != ' ')
{
return chessBoard[0][0];
}
if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]
&& chessBoard[0][2] != ' ')
{
return chessBoard[0][2];
}
if (is_Full(chessBoard))
{
return 'h';//和局
}
return ' ';//游戏继续
}