目录
1. 文件组织
采用多文件组织的方式:
test.c : 测试的逻辑(程序主要进程)
game.h : 函数的声明(在test.c中用到的函数的声明),以及#difine定义的常量,和所有用到的头文件
game.c : 函数的实现(函数的定义)
2. test.c 文件的架构
2.1 主函数
我们都知道,在进入一个游戏时,会先出现一个充满选项的菜单页面,而这个菜单是打开游戏就会有的,不需要进行选择,所以我们可以选择使用do...while语句,先进入循环,打印一个菜单,然后再判断怎么执行,故而有:
int main()
{
int input = 0;
do
{
menu();
printf("please choose:");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("exit game\n");
break;
default:
printf("input error,plase input again");
break;
}
}while(input);
return 0;
}
当玩家输入1时进入游戏,输入0时退出游戏,并且do...while循环判断条件为玩家输入的数字,当输入0时则退出循环,不再打印菜单。那么菜单该如何显示呢:
2.2 菜单
菜单的创建其实非常简单,只需要将信息显示出来就可以了:
void menu()
{
printf("**************************\n");
printf("**********1.game**********\n");
printf("**********0.exit**********\n");
printf("**************************\n");
}
2.3 游戏
接下来我们先说明游戏的具体流程:
2.3.1 棋盘初始化:
在我们创建game()函数后,首先要创建棋盘,我们这里是三子棋,所以需要一个3*3的二维数组
char board[3][3];
但是我们可以发现,这个程序已经写死了,因为如果有一天,我们不想要3*3的棋盘了,我们想玩五子棋,甚至十子棋,这个时候我们需要把程序中所有的3都改掉,未免太过麻烦,所以我们将行定义为3,将列定义为3
#define ROW 3
#define COL 3
这个时侯,我们创建的棋盘就可以改写成:
char board[ROW][COL];
同理,接下来需要写行和列的地方,都可以写成ROW和COL
创建好棋盘后,我们需要对棋盘初始化,让其中的空位都是空格:
void game()
{
char board[ROW][COL];
init_board(board,ROW,COL);
}
然后打印出棋盘,让玩家看到:
void game()
{
char board[ROW][COL];
init_board(board,ROW,COL);
print_board(board,ROW,COL);
}
这两个函数的具体实现会在后文中的game.c实现中详细介绍
2.3.2 下棋过程
玩家下棋→打印棋盘→判断输赢→游戏继续→电脑下棋→打印棋盘→判断输赢→游戏继续......
对这个流程明确以后,我们需要设计的函数就很清晰了:
玩家下棋
player_move(board,ROW,COL);
判断输赢
ret = is_win(board,ROW,COL);
电脑下棋
computer_move(board,ROW,COL);
2.3.3 判断输赢
电脑赢:#,因为电脑执#,判断函数返回值用所执棋子类型
玩家赢:*,同理
平局:Q,棋盘占满,但没有返回任何一种类型的棋子
游戏继续:C
ret为判断输赢函数的返回值
if (ret == '#')
printf("computer win\n");
else if (ret == '*')
printf("player win\n");
else if (ret == 'Q')
printf("draw\n");
至此,主函数构架完成,最终结果为:
#include "game.h"
void menu()
{
printf("**************************\n");
printf("**********1.game**********\n");
printf("**********0.exit**********\n");
printf("**************************\n");
}
void game()
{
char board[ROW][COL];
char ret = 0;
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("computer win\n");
else if (ret == '*')
printf("player win\n");
else if (ret == 'Q')
printf("draw\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("please choose:");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("exit game\n");
break;
default:
printf("input error,plase input again");
break;
}
}while(input);
return 0;
}
接下来我们开始详细介绍每个函数怎么声明和实现
3. 具体函数声明与实现
3.1 初始化棋盘
在game.h中声明函数:
void init_board(char board[ROW][COL],int row,int col);
在game.c中定义函数:
还记得我们的目的是把空位都初始化为空格
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.2 打印棋盘
同样在game.h中声明:
void print_board(char board[ROW][COL],int row,int col);
在game.c中定义:
void print_board(char board[ROW][COL],int row,int col)
{
int i = 0;
for(i=0;i<row;i++)//every row
{
int j = 0;
for(j=0;j<col;j++)//printf(" | | \n");
{
printf(" %c ",board[i][j]);//先打印棋盘中字符
if(j<col-1)
printf("|");//后打印分隔的'|',直到最后一个字符打印完就不用打印分隔符了
}
printf("\n");//打印完一行,然后换行
if(i<row-1)//printf("---|---|---\n");
{
for(j=0;j<col;j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
核心思路为在一行中打印每一列的内容,然后换行打印下一行中每一列的内容
打印每一列时,先打印棋盘中的字符,然后打印分隔符,再打印字符,再打印分隔符,最后一列不需要分隔符.
注意此时打印完一列后,这里的一列只是一半,因为我们在换行后还要打印横向的分隔符---,每一行需要呈现---|---|---的效果,如果不这样多做一行,上面的3个字符的空位就会被占用来打印横向分隔,所以我们需要加上一行,这时完整的一组应该是,这才算是完整的一大行
| |
---|---|---
同理横向分割在最后一行也不需要打印,所以才会有if(i<row-1)
需要说明的是我们一大行之中的i是不变的,只是用printf("\n")换的行
最后的效果呈现为:
| |
---|---|---
| |
---|---|---
| |
3.3 玩家下棋
首先要确保输入的坐标在合法的范围内,否则的话输出:输入做错误,请重试
玩家下棋是通过输入坐标,但是我们程序员都知道数组是从下标0开始的,但是普通人输入坐标肯定是从1,1这种开始输入的,所以我们在编写代码时要注意这一点,在下文中我也是使用x-1,y-1去指向真正数组中的位置
在坐标合法的情况下,如果该位置没有被下过棋,那么则放入*,否则则输出这个坐标已经被占用
void player_move(char board[ROW][COL],int row,int col)
{
printf("player move\n");
while(1)
{
printf("please input the coordinate:");
int x = 0;
int y = 0;
scanf("%d %d",&x,&y);
if(x>=1 && x<=row && y>=1 && y<=col)
{
if(board[x-1][y-1]==' ')
{
board[x-1][y-1]='*';
break;
}
else
printf("the coordinate are already occupied,plase input again\n");
}
else
{
printf("coordinate error\n");
}
}
}
3.4 判断输赢
在玩家下完棋后我们需要加一个判断输赢的程序,我们现在看来好像不需要,因为电脑还没下,但是当程序真正运行起来,下过几步后就需要判断了,所以在玩家和电脑下棋后都要各自判断一遍输赢
三子棋赢的方法也就是三个同样的棋子连成一条直线,当然这三个棋不能为空格
那么就有三行 三列 两条对角线这几种情况,返回符合情况的*或者#
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];
}
int j = 0;
for (j=0;j<col;j++)//判断三列
{
if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[0][j]!=' ')
return board[0][j];
}
//对角线
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 'Q';
//没有玩家或者电脑赢,也没有平局,游戏继续
return 'C';
}
当棋盘中棋子皆不符合上述情况,并且棋盘位置被全部占用时,则为平局,返回Q
当棋盘中棋子皆不符合上述情况,并且棋盘位置还有空余时,则继续,返回C
当然我们还需要一个判断棋盘是否占满的函数:
3.5 棋盘占满
int is_full(char board[ROW][COL],int row,int col)
{
int i = 0;
int j = 0;
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
不满返回0, 占满返回1
3.6 电脑下棋
void computer_move(char board[ROW][COL],int row,int col)
{
printf("computer move\n");
while(1)
{
int x = rand()%row;
int y = rand()%col;
if(board[x][y]==' ')
{
board[x][y]='#';
break;
}
}
}
电脑下棋就比较简单了,因为我们只考虑它下的地方合不合法,而不考虑它下的合不合理,毕竟只是一个非常简单的例子
那么核心思路和玩家下棋是一样的,空就填入#,唯一不同的地方在于我们要用到rand--srand,这组创造随机数的函数,在之前我们也是使用过的
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
......
4. 最后调整
至此,我们已经实现了这个小游戏,最后把所有头文件都放到"game.h",并且.c文件都包含上这个头文件
最后我们看一下各个文件的内容:
test.c:
#include "game.h"
void menu()
{
printf("**************************\n");
printf("**********1.game**********\n");
printf("**********0.exit**********\n");
printf("**************************\n");
}
void game()
{
char board[ROW][COL];
char ret = 0;
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("computer win\n");
else if (ret == '*')
printf("player win\n");
else if (ret == 'Q')
printf("draw\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("please choose:");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("exit game\n");
break;
default:
printf("input error,plase input again");
break;
}
}while(input);
return 0;
}
game.c:
#include "game.h"
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]=' ';
}
}
}
void print_board(char board[ROW][COL],int row,int col)
{
int i = 0;
for(i=0;i<row;i++)//every row
{
int j = 0;
for(j=0;j<col;j++)//printf(" | | \n");
{
printf(" %c ",board[i][j]);//先打印棋盘中字符
if(j<col-1)
printf("|");//后打印分隔的'|',直到最后一个字符打印完就不用打印分隔符了
}
printf("\n");//打印完一行,然后换行
if(i<row-1)//printf("---|---|---\n");
{
for(j=0;j<col;j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
void player_move(char board[ROW][COL],int row,int col)
{
printf("player move\n");
while(1)
{
printf("please input the coordinate:");
int x = 0;
int y = 0;
scanf("%d %d",&x,&y);
if(x>=1 && x<=row && y>=1 && y<=col)
{
if(board[x-1][y-1]==' ')
{
board[x-1][y-1]='*';
break;
}
else
printf("the coordinate are already occupied,plase input again\n");
}
else
{
printf("coordinate error\n");
}
}
}
void computer_move(char board[ROW][COL],int row,int col)
{
printf("computer move\n");
while(1)
{
int x = rand()%row;
int y = rand()%col;
if(board[x][y]==' ')
{
board[x][y]='#';
break;
}
}
}
int is_full(char board[ROW][COL],int row,int col)
{
int i = 0;
int j = 0;
for(i=0;i<row;i++)
{
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];
}
int j = 0;
for (j=0;j<col;j++)//判断三列
{
if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[0][j]!=' ')
return board[0][j];
}
//对角线
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 'Q';
//没有玩家或者电脑赢,也没有平局,游戏继续
return 'C';
}
game.h
#include <stdio.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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);
char is_win(char board[ROW][COL],int row,int col);
void computer_move(char board[ROW][COL],int row,int col);
完
标签:int,三子,game,实例,board,数组,printf,COL,ROW From: https://blog.csdn.net/2401_83634908/article/details/141101741