三子棋代码教学
三子棋算是比较早的益智互动游戏。那么我们怎么用C语言来解决呢?
这是利用代码之后的体现,我们在打代码之前,需要知道我们在游戏开始之前的界面长什么模样。那么我们在开始之前会有菜单函数来体现。
菜单函数
void menu()
{
printf("**********************\n");
printf("*** 1:play 0:exit ***\n");
printf("**********************\n");
}
这是个比较简单的函数体现。那么我们在结束之后,我们需要一个变量来获取使用者的一个选择。同时我们也需要利用这个变量来开始之后的决策。
首先,我们要判断用户的输入会有哪些情况。
第一种情况就是输入1,
第二种情况就是输入2,
第三种情况是为了防止程序出现bug而想到的,那就是,用户的输入不是1或者2.
这里我们很容易看出来,这是单一输入多元输出,我建议是使用switch()语句。同时我们需要把这个语句放到主函数当中。
代码如下
int main()
{
int m = 0;
srand((unsigned int)time(NULL)); //用于生成随机数,用于电脑下棋。我们先不管这个。
do
{
menu();
printf("请输入你的选择\n");
scanf("%d" , &m);
switch(m)
{
case 1:
game(); //用于游戏
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误字符\n");
break;
}
}while(m);
return 0;
}
这个代码有这么几个重点需要知道,其一:我们运用的是do循环语句。这个语句的好处就是十分贴切switch语句。变量m既控制了用户输入,又控制着循环的开始和结束。case 1 , case 2 和default控制着我上面说的三种形式。那么到现在为止,我们很轻松的完成了这个函数的表面工作。
之后我们需要完成细节。
第一点,我们要学会制造棋盘。
棋盘代码
char board[row][col] = {0}; //定义棋盘的数组,因为三子棋是二维的,所以创建二维数组。
void dyboard(char board[row][col] ,int x,int y) //用于打印棋盘的函数
{
int i = 0; //控制行
int j = 0; //控制列
for(i = 0;i < x;i++) //第一个循环,是把三子棋的一行看作一个单元,然后进行复制性质的打印。
{
for(j = 0 ; j<y;j++) //第二个循环,是把三子棋当中的一个个空格当作一个单元格进行复制打印。
{
printf(" %c " , board[i][j]); //这边的打印同时也为了输入。可以让用户把想输入的位置输入正确的符号。
if(j<y-1)
{
printf("|"); //这边一个判断是为了防止最后一个单元格也打印这个符号,我们可以清楚的发现最后一个单元格没有这个符号。
}
}
printf("\n"); //这边是打印好之后的回车,
for(j = 0;j <y;j++)
{
printf("---");
if(j<y-1)
{
printf("|"); //同上所述
}
}
printf("\n");
}
}
在打印时我们发现,我们利用的是分割的思想,把一个大的工程,分割成一个个小的工程,然后进行复制打印。
那么棋盘打印好周,我们为了能玩好一遍之后还能再玩一遍,而不破坏棋盘时,我们可以初始化我们的棋盘。
初始化棋盘函数
void cshboard(char board[row][col] ,int x,int y) //初始化棋盘函数
{
int i = 0; //i和j控制着行和列。
int j = 0;
for(i = 0;i<x;i++)
{
for(j = 0 ; j < y ; j++)
{
board[i][j] = ' '; //让board数组当中的每一个存储都变成空格
}
}
}
初始化棋盘之后我们就可以开始编写玩家该怎么进行游戏了。
玩家代码
void playermove(char board[row][col],int x,int y) //玩家代码
{
int ROW = 0;
int COL = 0;
while(1)
{
printf("玩家走\n请输入坐标。\n"); //玩家输入要下棋的位置
scanf("%d %d" , &ROW , &COL);
if(ROW>=1 && ROW<=x && COL>= 1 && COL<= y) //判断玩家下子的位置是否合法
{
if(board[ROW-1][COL-1] == ' ') //判断玩家下子的位置,之前是不是有过棋子。
{
board[ROW-1][COL-1] = '*'; //如果下子的位置合法,就下。
break;
}
else
{
printf("该坐标被占用\n");
}
}
else
{
printf("输入错误坐标。\n");
}
}
}
在玩家下子的时候我们有很多的判断,是为了防止代码出现bug。当玩家输入之后,我们就轮到了,电脑下子。
电脑下子的程序
void computermove(char board[row][col],int x,int y) //电脑下子的代码
{
int ROW = 0;
int COL = 0;
printf("电脑走\n");
while(1) //利用循环帮助,电脑下子。
{
ROW = rand()%row; //为了实现电脑下子的位置都是合法的。rand()函数可以利用之前用到的srand()和time()函数来帮忙实现真正的随机。
COL = rand()%col;
if(board[ROW][COL] == ' ') //判断电脑下子的位置是不是已经有棋子了。
{
board[ROW][COL] = '#';
break;
}
}
}
在电脑下子的代码里我们也需要保证下子的合法性。
当玩家和电脑都下子之后,我们需要一个函数来判断输赢。
判断输赢的函数
char pdsy(char board[row][col],int x ,int y)
{
int i = 0; //i和j控制着行列
int j = 0;
for(i = 0;i<x;i++)
{
if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') //判断是不是有行上相邻的三个棋子是相同的,如果是相同的就输出其中一个所代表的是什么图形,那么这个图形就获胜。
{
return board[i][0];
}
}
for(j = 0;j<y;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[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];
}
if(1 == full(board,row,col)) //当以上几种都没有发生的时候,我们就只剩下两种情况,一种是还没下完,一种是打成平手。所以我们利用自定义函数full()来判断这个函数。
{
return 'p'; //当棋盘都满时,我们可以输出平
}
else
{
return 'c'; //当棋盘没满的时候,我们就输出继续。让电脑和玩家继续下。
}
}
int full(char board[row][col],int x,int y) //判断棋盘是不是下满了。
{
int i = 0;
int j = 0;
for(i = 0;i < x;i++)
{
for(j = 0;j < y;j++)
{
if(board[i][j] == ' ') //判断是不是有空格。如果有就是没下满
{
return 0;
}
}
}
return 1;
当我们完成所有的一个个小部件之后我们就要组合一下。
组合代码
void game()
{
char ret; //用于存储判断输赢函数的输出结果
char board[row][col] = {0}; //定义数组
cshboard(board,row,col); //初始化棋盘
dyboard(board,row,col); //打印棋盘函数
while(1) //利用循环,将游戏开始。while(1)。是为了保证循环一直继续,直到遇到break;
{
playermove(board,row,col); //首先玩家先下棋
dyboard(board,row,col); //下好棋子之后我们要打印一遍棋盘,看棋子下在了哪里。
ret = pdsy(board,row,col); //判断我们下的子之后,会不会赢。
if(ret != 'c') //如果输出的不是C时,就结束循环,说明有结果了。
{
break;
}
computermove(board,row,col); //电脑下棋,同上。
dyboard(board,row,col);
ret = pdsy(board,row,col);
if(ret != 'c')
{
break;
}
}
if(ret == '#') //判断是谁获得胜利。
{
printf("电脑赢了!\n");
}
else if(ret == '*')
{
printf("玩家赢了!\n");
}
else if(ret == 'p')
{
printf("平局\n");
}
}
综上所述,所有函数就结合在了一起。三子棋也就出来。
接下来是完整代码
完整代码
//game.h 文件里的函数
#include<stdio.h>
#define row 3 //这是宏定义
#define col 3
void cshboard(char board[row][col] ,int x,int y); //我们看到所有函数的定义之后都有board数组和x , y。因为我们所有的函数都是围绕着棋盘来进行的。x和y分别代表行和列。
void dyboard(char board[row][col] ,int x,int y);
void playermove(char board[row][col],int x,int y);
void computermove(char board[row][col],int x,int y);
char pdsy(char board[row][col],int x,int y);
int full(char board[row][col],int x,int y);
//game.c文件里的函数,这里有各种小函数。
#include"game.h"
#include<time.h> //time函数所要用到的头文件
#include<stdlib.h> //srand函数所要用到的有文件
void cshboard(char board[row][col] ,int x,int y)
{
int i = 0;
int j = 0;
for(i = 0;i<x;i++)
{
for(j = 0 ; j < y ; j++)
{
board[i][j] = ' ';
}
}
}
void dyboard(char board[row][col] ,int x,int y)
{
int i = 0;
int j = 0;
for(i = 0;i < x;i++)
{
for(j = 0 ; j<y;j++)
{
printf(" %c " , board[i][j]);
if(j<y-1)
{
printf("|");
}
}
printf("\n");
for(j = 0;j <y;j++)
{
printf("---");
if(j<y-1)
{
printf("|");
}
}
printf("\n");
}
}
void playermove(char board[row][col],int x,int y)
{
int ROW = 0;
int COL = 0;
while(1)
{
printf("玩家走\n请输入坐标。\n");
scanf("%d %d" , &ROW , &COL);
if(ROW>=1 && ROW<=x && COL>= 1 && COL<= y)
{
if(board[ROW-1][COL-1] == ' ')
{
board[ROW-1][COL-1] = '*';
break;
}
else
{
printf("该坐标被占用\n");
}
}
else
{
printf("输入错误坐标。\n");
}
}
}
void computermove(char board[row][col],int x,int y)
{
int ROW = 0;
int COL = 0;
printf("电脑走\n");
while(1)
{
ROW = rand()%row;
COL = rand()%col;
if(board[ROW][COL] == ' ')
{
board[ROW][COL] = '#';
break;
}
}
}
char pdsy(char board[row][col],int x ,int y)
{
int i = 0;
int j = 0;
for(i = 0;i<x;i++)
{
if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for(j = 0;j<y;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[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];
}
if(1 == full(board,row,col))
{
return 'p';
}
else
{
return 'c';
}
}
int full(char board[row][col],int x,int y)
{
int i = 0;
int j = 0;
for(i = 0;i < x;i++)
{
for(j = 0;j < y;j++)
{
if(board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//三子棋实现.c的文件的代码,组合,game.c文件里面的所有函数。
#include"game.h"
#include"game.c"
void menu()
{
printf("**********************\n");
printf("*** 1:play 0:exit ***\n");
printf("**********************\n");
}
void game()
{
char ret;
char board[row][col] = {0};
cshboard(board,row,col);
dyboard(board,row,col);
while(1)
{
playermove(board,row,col);
dyboard(board,row,col);
ret = pdsy(board,row,col);
if(ret != 'c')
{
break;
}
computermove(board,row,col);
dyboard(board,row,col);
ret = pdsy(board,row,col);
if(ret != 'c')
{
break;
}
}
if(ret == '#')
{
printf("电脑赢了!\n");
}
else if(ret == '*')
{
printf("玩家赢了!\n");
}
else if(ret == 'p')
{
printf("平局\n");
}
}
int main()
{
int m = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入你的选择\n");
scanf("%d" , &m);
switch(m)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误字符\n");
break;
}
}while(m);
return 0;
}
以上就能发现,一个大的工程就是把大事化小,小事化了。三子棋实现的过程十分简单,至少没有什么大的问题,那么从此可以发现,人生何不是如此,我们四处奔波,遇到的大大小小的事情,最后都汇在一起成为人。
谢谢大家的阅读,我是Jack Chao。我爱代码,爱人生。