目录
>三子棋的实现要点
三字棋程序的关键点,以下。
·应用多文件的形式写代码
test.c —— 测试游戏部分。
game.c —— 游戏函数的实现部分。
game.h —— 游戏函数的声明部分。
·游戏不退出,玩了一把又一把
do—while循环。
·正式游戏
3*3的二维数组。
由空格元素替换为*或者#作为棋。
>具体代码实现
·游戏菜单
打印一个简易版的游戏菜单。
void menu()
{
printf("******************************\n");
printf("********** 1. play ***********\n");
printf("********** 0. exit ***********\n");
printf("******************************\n")
}
不需要返回值,void。别忘记\n。
·主函数使用菜单
在主函数中调用菜单
int main()
{
menu();
int input = 0;
printf("请选择>:");//提示输入
scanf("%d", &input);//输入 0,1或其他
return 0
}
选择后给予响应,使用switch语句来实现
switch (input)//switch()中的表达式只能是整型,字符型或枚举型表达式
{
case 1:
game();//玩游戏,game函数实现
break;//break在case语句中尤为重要,如果不加,则会继续执行下面的case
case 0:
printf("退出游戏");//提醒语句
break;
default://default可以放在switch中的任意位置,如果不是放在最后也要有break
printf("选择错误,请重新选择>:");
break;
}
·重复的选择玩游戏
游戏不退出,玩了一把又一把,循环来实现
int main()
{
int input = 0;//要放在循环外部
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{}
} while (input);//除了选择0退出游戏以外,无论选择什么都需要重新打印菜单
//计算while()中的表达式,如果值为真(非零),则继续执行循环体,如果值为假(零),则退出循环
return 0;
}
实现效果
·开始游戏
究其根本,三字棋游戏其实是一个3*3的二维数组。
*game函数
定义一个游戏函数game()来实现
void gamne()
{
char board[3][3] = { 0 };
InitBoard(board, 3, 3);//利用函数来初始化数组,将行和列都传参过去
}
*InitBoard函数
利用函数InitBoard进行数组的初始化,并在另一个文件game.h中进行函数的声明
此时创建的是一个3*3的数组,为防止3*3“棋盘”不够用需要更改的情况,我们采用宏定义的方式。
以便后期更改棋盘的格式。
#define ROW 3
#define COL 3
InitBoard(char board[ROW][COL], int row, int col);
要使用另一个文件中的宏定义,要包含自己创建的这个头文件。这样任何需要行列的地方都可以使用ROW,COL。
函数声明结束,接下来在第三个文件game.c中对函数进行实现。
注意:在第三个头文件中仍然要包含自己创建的game.h文件。
void InitBoard(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] = ' ';
}
}
}
此时数组已经全部初始化为空格。
*DisplayBoard函数
利用DisplayBoard函数来打印验证是不是数组均已初始化为空格,依旧在game.h文件中进行声明,在game.c文件中进行实现。
void DisplayBoard(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]);//char类型的用%c进行打印
}
printf("\n");//打印完一行记得换行
}
}
运行
此时打印了数组空格,但我们看不到,打印X更直观
#打印棋盘格子(行灵活)
加上分割线,只需一层行循环。数据分割线,数据分割线,数据分割线。
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);//char类型的用%c进行打印
printf("---|---|---");
printf("\n");
}
效果
去掉最后一行的分割线,在循环内部加条件if。
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);//char类型的用%c进行打印
if (i < row - 1)
printf("---|---|---\n");
}
效果
#列灵活
列固定死了,让列变得灵活起来。
观整个棋盘可以看成是一行数据,一行分割线,单看一行又可以看成数据分割线,数据分割线。
上一个打印数据和打印分割线的代码均要第二步分割。
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");
//打印分割线(整体的第二行),细分处理
if (i < row - 1)//分割线在整体中本来就是if语句控制的,所以这个循环要在if语句中
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");//同上最后一行不打印
}
printf("\n");
}
}
打印7*7的效果
·下棋
*玩家下棋
#PlayerMove函数
向数组中换数据,仍然需要将数组的行列传参到函数中
void PlayerMove(char board[ROW][COL], int row, int col);
具体函数实现,简单框架
printf("请输入下棋的坐标(中间使用空格)>:\n");
scanf("%d %d", &x, &y);
//坐标合法
if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家不是程序员,从1开始
{
}
//坐标非法
else
{
printf("坐标非法,重新输入>:\n");
}
如果坐标非法,则重新输入,循环。
while (1)
{
printf("请输入下棋的坐标(中间使用空格)>:\n");
scanf("%d %d", &x, &y);
//坐标合法
if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家不是程序员,从1开始
{
}
//坐标非法
else
{
printf("坐标非法,重新输入>:\n");
}
}
当玩家坐标合法时,且不被占用的情况下才可下棋,即元素是空格的时候。
while (1)
{
printf("请输入下棋的坐标(中间使用空格)>:\n");
scanf("%d %d", &x, &y);
//坐标合法
if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家不是程序员,从1开始
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,不能落子,请重新输入坐标>:\n");//重新落子进入循环没有break
}
}
//坐标非法
else
{
printf("坐标非法,重新输入>:\n");
}
}
下棋效果调用DisplayBoard函数展示,可添加换行增加可读性
InitBoard(board, ROW, COL);//利用函数来初始化数组,将行和列都传参过去
DisplayBoard(board, ROW, COL);
printf("\n");
PlayerMove(board, ROW, COL);
printf("\n");
DisplayBoard(board, ROW, COL);//下棋之后再次调用,展示下棋结果
printf("\n");
#检验报错
玩家落子超过范围,落子被占用的情况
while循环,玩家一直下
while(1)
{ PlayerMove(board, ROW, COL);
printf("\n");
DisplayBoard(board, ROW, COL);//下棋之后再次调用,展示下棋结果
printf("\n");}
*电脑下棋
#ComputerMove函数
电脑随机下棋,与玩家下棋情况相似。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;//电脑不似玩家,坐标可以控制为0~row-1
int y = 0;//0~col-1
printf("电脑下棋>:\n");
}
#rand函数,srand函数,time函数
rand函数来生成随机数,使用rand函数需要调用srand函数。
srand函数需要包含<stdlib.h>头文件,time函数需要包含<time.h>头文件。
头文件的包含也可以嵌套。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋>:\n");
x = rand() % row;
y = rand() % col;//%上最大值,控制范围
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
#检验报错
电脑落子范围确定,只会出现落子被占用的情况。如果落子被占用只需循环重新生成随机数几个。
while (1)
{
x = rand() % row;
y = rand() % col;//%上最大值,控制范围
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
·判断输赢
#Iswin函数
玩家赢,电脑赢,平局,游戏继续。
玩家赢返回“*”,电脑赢返回“#”,平局返回“Q”,游戏继续返回“C”。
返回不同的值代表不同的状态。
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("你赢啦!\n");
else if (ret == '#')
printf("你输了。\n");
else
print("平局。\n");
}
判断行
char Iswin(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 (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[2][i] == board[1][i] && board[0][i] != ' ')
{
return board[0][i];//前后呼应,返回什么谁就赢了
}
}
判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[1][1];//前后呼应,返回什么谁就赢了
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
{
return board[1][1];//前后呼应,返回什么谁就赢了
}
·判断平局
没人赢且棋盘满了
#Isfull函数
int Isfull(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;
if (Isfull(board, row, col) == 1)
{
return 'Q';
}
return 'C';
成了