希望文章能对你有所帮助,有不足的地方请在评论区留言指正,一起交流学习!
目录
3.3.2 init_board()初始化棋盘
1.游戏介绍
规则:游戏双方对战,双方依次在9宫格棋盘上摆放棋子,分为'X'和'O'两种。
1.率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了。
2.棋盘填满的情况下视为平局。
代码存放处
这个是我编写的程序,如有错误请指正【免费】C语言三子棋(密码:1234)资源-CSDN文库
2.设计思路
我们采用C语言,由于程序较为复杂,所以我们采用模块化来写,将整个程序分为三个文件
1. test.c为测试程序,主要是测试的逻辑,就是子程序执行的顺序
2.game.c 主要编写游戏运行的所有子函数程序
3.game.h 对库函数以及game.c中的函数进行声明。
如果不懂VS软件中项目是如何运行并在组装在一起,看一看看C语言笔记(函数篇一)-CSDN博客这个中函数的声明。
分为两个模块
test.c为测试模块
game.c和game.h是游戏模块。
3.程序的实现
一、设计要求
1.有开始菜单,并且有是否进入游戏的选择,输入1就进入,0就退出。
2.对手是电脑。
3.可以判断输赢,并输出。
3.1主函数编写
首先我们在测试程序(test.c)中完成main()函数,要求:主函数中的程序要尽量的少,因此我们会将程序的测试放在了test()的子函数中,当然这个子函数也在test.c文件中
int main()
{
test();
return 0;
}
3.2 test()函数编写
test函数中式的主要作用
调用游戏菜单函数和判断是否进入游戏函数,menu()是游戏菜单的打印
程序的逻辑:
1.switch语句分情况 在输入1情况下开始游戏,并执行game()函数中的程序
2.要求在输入数字的时候是可以多次输入的,因此我们在采用的do......while的循环结构,这样就可以输入多次,将input输入的数字为判断条件,正好符合 数字 0退出游戏的设定。
下面这段代码是根据时间戳随机生成随机数字的起点,和rand()函数配合使用就可以生成一个随机数了。
srand((unsigned int)time(NULL));
void test()
{
srand((unsigned int)time(NULL));
menu();
int input = 0;
do
{
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game(); //输入1的情况下进入game子函数中
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,重新输入\n");
break;
}
}
while (input); //将input作为判断条件符合程序要运行的方式
}
menu()函数,作用仅仅就是在屏幕上打印菜单而已。
void menu()
{
printf("************************\n");
printf("******** 1.play ********\n");
printf("******** 2.exit ********\n");
printf("************************\n");
}
3.3game()函数编写
game函数的作用
编写game.c源文件中的子程序执行的逻辑,如何实现三子棋游戏。
3.3.1 test()函数整体逻辑
所有子函数必须再头文件game.h中声明,声明的格式就是
//初始化数组,将数组所有元素改为 空格
void init_board(char board[ROW][COL], int row,int col);
//打印棋盘
void print_board(char board[ROW][COL], int row, int col);
//玩家输入
void player_mover(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);
程序的逻辑
(1)定义的ROW ,COL
我们在game.h的文件中定义的ROW ,COL,因为要在两个源文件中使用;
(2)创建一个三行三列的数组
(3) 初始化棋盘,就是打出棋盘的最初模样,将数组的所有元素改成符号空格
(4) 打印整个棋盘 ,将整个棋盘打印出来,包括数组的元素
(5) 玩家输入函数,在玩家输入坐标后,再次打印整个棋盘
(6) 打印整个棋盘
(7)输赢的判断函数的调用
(8)电脑输入 ,电脑是随机输入的,这个时候我们就用到那个随机生成的数。
(9)打印整个棋盘
(10) 判断输赢函数的调用
(11) 由于我们要多次的输入和打印棋盘,因此我们采用while(1)的循环,当符合某一条件的情况下跳出棋盘。
(12) 最后就是输出玩家胜利和电脑胜利的if语句。
#define ROW 3
#define COL 3
上面game.h的文件中定义的ROW ,COL,这种是常量,要是修改的话,直接将3 改为10 等等
void game()
{
char board[ROW][COL];
//初始化数组
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
char ret ;
while (1)
{
//玩家下棋
player_mover(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");
}
if (ret == '#')
{
printf("电脑胜利\n");
}
if (ret == 'Q')
{
printf("平局\n");
}
}
//接下里的程序是要有返回值的,
//定位玩家赢返回'*'
//电脑赢 返回'#'
//平局 返回'Q'棋盘已经满
//继续游戏 返回'C'
3.3.2 init_board()初始化棋盘
使用两次for循环直接将board[ ][ ]中的所有元素改为 符号空格
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] = ' '; //空格是字符
}
}
}
3.3.3 print_board( )初始化棋盘
下面的代码使用了一个for循环,打印三次,一次的同时打印数组元素,在打印---分割线(可以优化的)
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < col; i++)
{
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < row - 1)
{
printf("---|---|---\n");
}
}
printf("\n");
}
打印出来的结果是
3.3.4 player_mover( ) 玩家下棋
逻辑:
我在这里实现采用了 while和break组合的循环,goto语句,站在玩家的立场上
1.首先玩家输入变量,确定输入那个位置
2.使用while(1)语句,
3.在语句中使用if else语句判断输入的条件,要进行什么修改,行和列减一是必然的
4. goto语句,在这里输入错误或者输入位置已经使用过会重新进入循环
void player_mover(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋\n");
//站在玩家的立场上是第一行第一列
flag:
while (1)
{
printf("请输入坐标\n");
scanf("%d %d", &x, &y);
if (x >= 1 && y >= 1 && x <= row && y <= col)
{
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("坐标已经被占用,请重新输入\n");
goto flag;
}
}
else
{
printf("无效坐标,重新输入\n");
goto flag;
}
}
}
3.3.5 computer_move( )电脑输入
逻辑
1. 和3.3.4一样的,rand()和srand函数配合生成随机数组,对于3取模以后,只能产生小于3的数字
2. 使用while(1)和break实现错误输入再输入的情况,要配合goto语句
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
flag1:
while (1)
{
int x = rand() % row;
int y = rand() % col;
printf("%d %d\n", x,y);
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
else
{
goto flag1;
}
}
}
3.3.6 is_win( )判断输赢编写
首先是有两个函数构成的is_full仅仅对于is_win有作用,因此就将他放在了game.c文件中。
逻辑
1.判断行是否相等且不等于空格
2.判断列是否相等且不等于空格
3.判断对角线是否相等且不等于空格
4.判断棋盘是否填满,并且有返回值
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][2]!=' ')
return board[i][0];
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i]!= ' ')
return board[0][0];
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2]&& board[2][2]!= ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0]&& board[2][0]!= ' ')
{
return board[1][1];
}
int ret = is_full(board, row, col);
if (ret == 0)
{
return 'C';
}
else
return 'Q';
}