首先,先做前期准备完之后——再创建一个源文件,用来存放函数定义;和一个头文件,用来存放函数声明。
然后,搭建框架(其实,与前面所教的猜数字游戏差不多)
1、任何程序都是从main主函数开始进入的
int main(){
tesr();
return 0;
}
2、用test函数来写游戏的最先开始执行的步骤
void test(){
menu();
}
3、这里先写一个menu菜单函数,来制作游戏的菜单选择。
void menu(){
printf("****************************");
printf("****1、play 2、exit****");
printf("****************************");
}
有了选择之后,就需要一个提示,让用户进行选择:
printf("请选择:");
既然有选择,那么就需要用户在页面中输入相对应的数字;
所以,这里用scanf函数来接收用户输入的数值,用input整形变量来进行存储。
int input=0;
scanf("%d",&input);
4、用户进行选择之后,就要判断用户的选择是否正确(用户可能会选择1和2以外的数字),选择之后,需要提示。
switch(input){
case 1:
printf("三子棋\n");
break;
case 2:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选:");
break;
}
5、我们知道游戏一开始肯定要先让用户体验一把,在做判断是否需要继续玩,所以,这里用到了do...while循环语句。(至少先进入一次循环)
do{
menu();
printf("请选择:");
scanf("%d",&input);
switch(input){
case 1:
printf("三子棋\n");
break;
case 2:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选:");
break;
}
}while(input);
至于,为什么要在while()括号里条件判断写input,是因为如果input为0的话,就为假,则跳出循环;若为1或其他数字就继续循环。
6、接下来,就是要去编写我们这样关于三子棋游戏的游戏过程,是一个复杂的过程(要跟电脑下),所以这里我们就用game()函数来封装我们这样一个过程。(game函数就是游戏的逻辑)
void game(){
}
游戏的整个算法实现
7、三子棋游戏的逻辑思路:在九宫格中,跟电脑下,玩家执行一步,电脑执行一步;当出现有三子在九宫格中连成一条线的时候,就判断胜利。
这个过程中,玩家用“ * ”号表示;电脑用“ # ”号表示。
在这个过程中,就需要清楚了解数组的使用和游戏算法的思路。
而九宫格的表示方法,就是用到二维数组(3行3列),因为玩家和电脑在九宫格里面下的棋子,其实就相当于在二维数组中存储数据——
char board[3][3]={0};
因为我们存储的是“*”“#”字符,所以数组元素用char来表示。
【注:有关二维数组每一个格子的表示是什么意思,请翻看上一章的知识点】
但在三子棋游戏中这样写二维数组并没有什么技术含量,后期还可能会出现一些问题。
可以这样做,将二维数组中的行和列单独定义,即——
在新建的game.h头文件中去定义
#define ROW 3
#define COL 3
然后在源文件中将
char board[3][3]={0};改为char board[ROW][COL]={0};
这样以后,想要改变二维数组中的行和列的时候,可以去game.h头文件中更改;
甚至,在未来整个工程中,只要涉及到行和列的地方,也可以方便的更改。
注:想要引用game.h头文件里的符号,就需要在源文件中包含这样的头文件
#include"game.h"
但是,这样所创建的二维数组并不是我们想要的九宫格,一开始的九宫格我们想要它里面在视觉上给我们的直观感受是没有任何的数值的。
如何实现?这里我们就用空格来代替
所以——
InitBoard(board,ROW,COL);
我们去写一个初始化二维数组的函数InitBoard();
然后去game.h头文件里去声明
void InitBoard(char board[ROW][COL],int row,int col);
然后去game.c源文件中去定义(使用)
void InitBoard(char board[ROW][COL],int row,int col){
int i=0;
int j=0;
for(j=0;i<row,i++){
for(j=0;j<col,j++){
bord[i][j]=' ';
}
}
}
之后就是要去打印我们想要的九宫格,如何打印?
这里用到我们自定义的函数——DisplayBoard();
DisplayBoard(board,ROW,COL);
然后去game.h头文件中去定义
DisplayBoard(char board[ROW][COL],int row,int col);
在屏幕上输出九宫格的思路:
所表示的意思就是一行数据,一行分割
如果用printf来打印,就需要5个,这样的话,代码写起来就没有什么计算含量(当我们想要打印更大的棋盘时,就需要多个printf);因此,我们这样做——
可以把数据加分割行当成第一组,第二组也一样,第三组的时候,只是少了分割行;
这样有几组跟我们的行数有关系(3行数据对应三组)
【注:其实就是在写三个一维数组】
如何去写?
DisplayBoard(char board[ROW][COL],int row,int col){
int i=0;
for(i=0;i<row;i++){
//1、打印数据
printf(" %c | %c | %c \n",bord[i][0],board[i][1],board[i][2]);
//2、打印分割符
if(i<row-1)
printf("---|---|---\n");
}
}
这里为什么要printf(" %c | %c | %c \n",bord[i][0],board[i][1],board[i][2]);加上空格后再打印%c,这是因为——与分割符对应,让打印的字符放在中间位置,对应下面中间的分割符,以此达到美观的效果。
这里提一点:如果我们注释掉初始化部分,会发现,打印结果还是一样,这是因为在最先开始定义二维数组的时候,我们就已经初始化为0了
char board[ROW][COL]={0};
而0其实也是一种不可打印字符,打印出来也看不见;虽然,这样跟初始化为空格的效果蛮相似的,但还是不能这样去做,还是用空格最合适。
这样,在最开始初始化不为0的时候,是不会有问题的,也不需要关注最开始时数组里面放的内容是什么,因为后面都被我们初始化为空格。
回到打印部分,这里提一点,打印部分的代码这样写并不好,有局限性;当我们想要打印10*10的的格子布局时
将ROW和COL的数值改为10和10,会发现,它只打印10行3列,行没有问题,但列就不是我们想要的效果,这时,就需要优化我们的代码部分了——
要如何才能让棋盘的布局得到我们想要改变的样子?
优化打印的部分——
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++){ //1、打印一行数据
printf(" %c ",board[i][j]);
if(j<col-1)
printf("|");
}
printf("\n");
//2、打印分割行
if(i<row-1){
for(j=0;j<col;j++){
printf("---");
if(j<col-1)
printf("|");
}
pinrf("\n");
}
}
}
分析一下:最先开始我们是将数据和分割符当作一块,总共3块嘛,相当于创建了三个一维数组,然后将数据和分割符进行打印
然后这里我们采用将每一行中的每一列分为3块,即——
然后就是第一块是:空格+数据+空格+|;第二块也一样,但是第三块最后少了“|”
所以这里的 j 就是表示列。
int j=0;
for(j=0;j<col;j++){ //1、打印一行数据
printf(" %c ",board[i][j]);
if(j<col-1)
printf("|");
}
这里需要换行
pinrf("\n");
然后就是打印分割符了,但要注意,这里我们因为只有两行分割符,所以这里我们只需要两行即可
就用到判断的方法
if(i<row-1){
}
后面分割符也是跟数据打印一样,分三列,三列在分为三块,即——
for(j=0;j<col;j++){
printf("---");
if(j<col-1)
printf("|");
}
到这里,我们知道用行分三块的方法有局限性;用列分为三块的方法(将数据与分割符分开打印)就能很好解决我们的问题。
test.c源文件
void menu(){
printf("***********************");
printf("***1、play 0、exit***");
printf("***********************");
}
viod game(){
char board[ROW][COL]={0};
InitBoard(board,ROW,COL);
DisplayBoard(board,ROW,COL);
}
void test(){
int input=0;
do{
menu();
printf("请选择:");
scanf("%d",&input);
switch(){
case 1:
game();
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误,请重新选择:");
break;
}
}while(intput);
}
int main(){
test();
return 0;
}
game.h头文件
//用来函数声明
#define ROW 3
#define COL 3
#include<stdio.h>
void InitBoard(char board[ROW][COL],row,col);
void DisplayBoard(char board[ROW][COL],row,col);
game.c源文件
//函数定义
void InitBoard(char board[ROW][COL],row,col){
int i=0;
for(i=0;i<row;i++){
int j=0;
for(j=0;j<col;j++){
board[i][j]=' ';
}
}
}
void DisplayBoard(char board[ROW][COL],row,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");
if(i<row-1){
for(j=0;j<col;j++){
printf("---"); if(j<col-1) printf("|");
}
printf("\n");
}
}
}
这里为什么要将#include<stdio.h>放在game.h头文件,这是因为不管是game.c源文件,还是test.c源文件,都用到printf函数,因此,放在game.h中两边都可以引用。