C语言初始三子棋

目录

一、文件的创建

二、玩家游戏界面的创建

        1. 菜单函数的创建

        2. 玩家选择的创建

三、游戏的进程与判断输赢条件

        1. 游戏规则

        2. 棋盘的定义

        3. 游戏棋盘的初始化

        4. 打印出棋盘格式

        5. 玩家进行游戏

        6.判断游戏结局(

                                                1. 测试一行能不能赢

                                                2. 测试一列能不能赢

                                                3. 测试两个对角线能不能赢

                                 )

四、加强部分

五、代码部分

        game.c

        game.h

        test.c


一、文件的创建

我们可以创建三个文件,两个源文件,一个头文件。

头文件game.c用来声明函数,源文件test.c用来测试,game.c文件用来实现游戏函数

 

二、玩家游戏界面的创建

        1. 菜单函数的创建

        这里我们简单编辑一个菜单函数,打印出一个方便于玩家选择的界面

void menu()
{
	printf("*********************\n");
	printf("********1.play*******\n");
	printf("********0.exit*******\n");
	printf("*********************\n");
}

     

        测试打印的结果为

         2. 菜单函数创建完之后,来创建玩家选择函数,让玩家进行选择

        

int n = 0;
	do//采用do-while循环,因为玩家最少进行一次游戏
	{
		menu();//菜单函数
		scanf_s("%d", &n);//让玩家输入数字,进行选择
		switch (n)//判断玩家输入满足下面哪一个条件
		{
		case 1:
			printf("三子棋游戏:\n");
			game();
			break;//玩家输入1就打印三子棋游戏字样,并且竟然game函数进行三子棋游戏。游戏结束后自动跳出,玩家重新选择是否继续游戏
		case 0:
			printf("退出游戏");
			break;//玩家输入0,则退出游戏
		default :
			printf("输入错误,请重新输入:");//玩家如果输入1和0之外的元素,则告诉玩家输入错误,请重新输入元素
			break;
		}
	} while (n);//;不能掉

         将玩家选择界面创建好了放在主函数main里面

         

int main()
{
	int n = 0;
	do//采用do-while循环,因为玩家最少进行一次游戏
	{
		menu();//菜单函数
		scanf_s("%d", &n);//让玩家输入数字,进行选择
		switch (n)//判断玩家输入满足下面哪一个条件
		{
		case 1:
			printf("三子棋游戏:\n");
			game();
			break;//玩家输入1就打印三子棋游戏字样,并且竟然game函数进行三子棋游戏。游戏结束后自动跳出,玩家重新选择是否继续游戏
		case 0:
			printf("退出游戏");
			break;//玩家输入0,则退出游戏
		default :
			printf("输入错误,请重新输入:");//玩家如果输入1和0之外的元素,则告诉玩家输入错误,请重新输入元素
			break;
		}
	} while (n);//;不能掉
}

        

         主函数编辑完之后接下来就进入game函数,也就是游戏环节,开始编辑游戏环节代码

三、游戏的进程与判断输赢条件

        1. 游戏规则

        

        2. 棋盘的定义

        三子棋棋盘是3*3的格式,但是要注意是“井”字型,周围都是开口型的

#define ROW 3    // 3是棋盘的行数,可以随意改变数字
#define COL 3    // 3是棋盘的列数,可以随意改变数字

        在头文件game.h里声明,因为后面要用到很多次,我们在game.c和test.c里面引用头文件就行了,所以我们为了方便可以在头文件把所有要使用的函数的声明一下,然后直接引用就行

声明stdio库函数

#define ROW 3    // 3是棋盘的行数,可以随意改变数字
#define COL 3    // 3是棋盘的列数,可以随意改变数字

#include<stdio.h>

引用头文件,要加" "号

#include"game.h"

        现在创建一个二维数组来定义棋盘,在test.c的game函数里定义

char qp[ROW][COL] = { 0 };//定义棋盘时,ROW也就是行可以省,但是COL也就是列不能省,推荐大家都带上

        3. 游戏棋盘的初始化
          定义一个函数进行传参

initqp(qp, ROW, COL);//初始化棋盘,不管之前棋盘里放了什么,全部都初始化为空格

在头文件里接收

//初始化棋盘
void initqp(char qp[ROW][COL],int row,int col);//形参要小写

在game.c文件里实现,将定义的二维数组棋盘全部初始化为空格

#include"game.h"
void initqp(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			qp[i][j] = ' ';
		}
	}
}

初始化完棋盘后就可以打印出棋盘格式

        4. 打印出棋盘格式

        棋盘图像如图:

//棋盘:
 //   |   |
 //---|---|---
 //   |   |       
 //---|---|---
 //   |   |

        test.c:

displayqp(qp,ROW,COL);//打印棋盘

        game.h:

//打印棋盘
void displayqp(char qp[ROW][COL], int row, int col);

        game.c:

void displayqp(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;//定义两个变量用来遍历数组
	for (i = 0; i < row ; i++)//确定要打印多少行
	{
		for (j = 0; j < col; j++)//打印一行数据
		{                                                    //打印行时,可以把   |   |   看成一组数据
			                                                 //                ---|---|---

			printf(" %c ", qp[i][j]);//%c左右两个位置是空格,确保元素在中间位置                                       
			if (j < col - 1)//避免打印出棋盘最右边的一行|  
			{                                                             
				printf("|");                                         
			}
		}//此时打印出的是:    |   |   

		printf("\n");//和下面的printf("\n")共同把棋盘展开打印,否则棋盘会被打印在一行上面,就像下面那样:
                    //未输入printf("\n")的棋盘:    |   |   ---|---|---   |   |   ---|---|---   |   |

		if (i < row - 1)//打印分割行             
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//避免打印出第3行的分割行   
				{                                                               
					printf("|");                                                
				}//此时打印出的是:---|---|---
			}
			printf("\n");
		}
	}
}

        测试棋盘图像

         5. 玩家进行游戏

        玩家下一步,就打印一次棋盘状况

        test.c:

player(qp,ROW,COL);//玩家下棋
		displayqp(qp, ROW, COL);//打印棋盘

        game.h:

//玩家走
void player(char qp[ROW][COL], int row, int col);

        game.c:

void player(char qp[ROW][COL], int row, int col)
{
	int x = 0;//定义两个变量来表明玩家落子的位置
	int y = 0;//x,y是横纵坐标
	printf("玩家走:\n");
	while (1)//坐标合法就跳出
	{
		printf("请输入下的坐标:");
		scanf_s("%d%d", &x, &y);//玩家输入x,y坐标
		//判断x,y坐标合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家不知道下标是从0开始的,所以x,y都要从1开始
		{
			if (qp[x - 1][y - 1] == ' ')//x-1,y-1才对应到数组里面的元素
			{
				qp[x - 1][y - 1] = '*';//玩家落子,下一个*
				break;
			}
			else
			{
				printf("该坐标已被占用\n");//这个位置已经有棋子了
			}
		}
		else
		{
			printf("坐标非法,请重新输入:");//输入坐标超过棋盘范围
		}
	}
}

        玩家走一步之后的图像

         电脑进行自动下棋,并打印出棋盘

        test.c:

computer(qp, ROW, COL);//电脑下棋
		displayqp(qp, ROW, COL);//打印棋盘

        game.h:

//电脑走
void computer(char qp[ROW][COL], int row, int col);

        game.c:

void computer(char qp[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;//定义两个变量来表示电脑落子坐标
	printf("电脑走:\n");//电脑随机走,哪里有空位就走哪里
	while (1)
	{
		x = rand() % row;//电脑生成坐标在0到2之间,同时rand()%3余的值在0到2之间
		y = rand() % col;
		if (qp[x][y] == ' ')//x,y已经合法了,不用再减一
		{
			qp[x][y] = '#';//电脑落子,下一个#
			break;
		}
	}
	
}

注意:game.c里面用到了rand,所以要引用相对应的函数

        test.c:

int main()
{
	int n = 0;
	srand((unsigned int)time(NULL));//时间戳,用来生成随机,要引用time函数,该语句整局只用一次,所以可以放在开头处
					 //unsigned int 将time返回的值强制转化成无符号整形类型,用来作为srand随机数生成器
	do//采用do-while循环,因为玩家最少进行一次游戏
	{
		menu();//菜单函数

        game.h:

#define ROW 3    // 3是棋盘的行数,可以随意改变数字
#define COL 3    // 3是棋盘的列数,可以随意改变数字

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

        测试对弈下棋

 

        6.判断游戏结局

        情况1. 玩家或者电脑每次走一步就判断是否赢了

        情况2. 棋盘满了,平局

        game.h:

//可以告诉我们4种状态:
//1.玩家赢   -->'*'
//2.电脑赢   -->'#'
//3.平局     -->'P'
//4.游戏继续 -->'C'
char win(char qp[ROW][COL], int row, int col);//要返回字符,所以说要用char类型返回

        test.c:

while (1)//无限循环下棋,直到出现下面的情况就跳出
	{
		player(qp,ROW,COL);//玩家下棋
		displayqp(qp, ROW, COL);//打印棋盘
		ret = win(qp, ROW, COL);//判断玩家是否赢了
		if (ret != 'C')//如果返回的ret不是字符c
		{
			break;//跳出循环
		}
		computer(qp, ROW, COL);//电脑下棋
		displayqp(qp, ROW, COL);//打印棋盘
		ret = win(qp, ROW, COL);//判断电脑是否赢了
		if (ret != 'C')//如果返回的ret不是字符c
		{
			break;//跳出循环
		}
	}
	if (ret == '*')//ret返回字符*
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')//ret返回字符#
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");//ret返回字符p
	}
}

        game.c:

//判断棋盘满没满,返回1表示满了,返回0表示没满
int full(char qp[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 (qp[i][j] == ' ')//棋盘上还存在空格
			{
				return 0;//棋盘没满
			}
		}
	}
	return 1;//棋盘满了
}
char win(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)//判断3行
	{
		if (qp[i][0] == qp[i][1] && qp[i][1] == qp[i][2] && qp[i][1] != ' ')//判断第几行字符相同,排除游戏开始存在的空格
		{
			return qp[i][1];//返回*就表示同一行3个字符相同--->玩家赢,返回#,P,C同理
		}
	}
	for (i = 0; i < col; i++)//判断3列
	{
		if (qp[0][i] == qp[1][i] && qp[1][i] == qp[2][i] && qp[1][i] != ' ')//判断第列行字符相同,排除游戏开始存在的空格
		{
			return qp[1][i];//返回*就表示同一行3个字符相同--->玩家赢,返回#,P,C同理
		}
	}
	//判断两个对角线
	if (qp[0][0] == qp[1][1] && qp[1][1] == qp[2][2] && qp[1][1] != ' ')
	{
		return qp[1][1];//返回* 就表示同一行3个字符相同--->玩家赢, 返回#,P,C同理
	}
	if (qp[2][0] == qp[1][1] && qp[1][1] == qp[2][2] && qp[1][1] != ' ')
	{
		return qp[1][1];//返回* 就表示同一行3个字符相同--->玩家赢, 返回#,P,C同理
	}
	//判断是否平局
	if (1 == full(qp, ROW, COL))
	{
		return 'P';//返回字符P平局
	}
	return 'C';//返回字符C游戏继续
}

        游戏试玩结果

 四、加强部分

五、代码部分

       game.c:

#include"game.h"
void initqp(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			qp[i][j] = ' ';
		}
	}
}
 //棋盘:
 //   |   |
 //---|---|---
 //   |   |       
 //---|---|---
 //   |   |   
void displayqp(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;//定义两个变量用来遍历数组
	for (i = 0; i < row ; i++)//确定要打印多少行
	{
		for (j = 0; j < col; j++)//打印一行数据
		{                                                    //打印行时,可以把   |   |   看成一组数据
			                                                 //                ---|---|---

			printf(" %c ", qp[i][j]);//%c左右两个位置是空格,确保元素在中间位置                                       
			if (j < col - 1)//避免打印出棋盘最右边的一行|  
			{                                                             
				printf("|");                                         
			}
		}//此时打印出的是:    |   |   

		printf("\n");//和下面的printf("\n")共同把棋盘展开打印,否则棋盘会被打印在一行上面,就像下面那样:
                    //未输入printf("\n")的棋盘:    |   |   ---|---|---   |   |   ---|---|---   |   |

		if (i < row - 1)//打印分割行             
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//避免打印出第3行的分割行   
				{                                                               
					printf("|");                                                
				}//此时打印出的是:---|---|---
			}
			printf("\n");
		}
	}
}
void player(char qp[ROW][COL], int row, int col)
{
	int x = 0;//定义两个变量来表明玩家落子的位置
	int y = 0;//x,y是横纵坐标
	printf("玩家走:\n");
	while (1)//坐标合法就跳出
	{
		printf("请输入下的坐标:");
		scanf_s("%d%d", &x, &y);//玩家输入x,y坐标
		//判断x,y坐标合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家不知道下标是从0开始的,所以x,y都要从1开始
		{
			if (qp[x - 1][y - 1] == ' ')//x-1,y-1才对应到数组里面的元素
			{
				qp[x - 1][y - 1] = '*';//玩家落子,下一个*
				break;
			}
			else
			{
				printf("该坐标已被占用\n");//这个位置已经有棋子了
			}
		}
		else
		{
			printf("坐标非法,请重新输入:");//输入坐标超过棋盘范围
		}
	}
}
void computer(char qp[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;//定义两个变量来表示电脑落子坐标
	printf("电脑走:\n");//电脑随机走,哪里有空位就走哪里
	while (1)
	{
		x = rand() % row;//电脑生成坐标在0到2之间,同时rand()%3余的值在0到2之间
		y = rand() % col;
		if (qp[x][y] == ' ')//x,y已经合法了,不用再减一
		{
			qp[x][y] = '#';//电脑落子,下一个#
			break;
		}
	}
	
}
//判断棋盘满没满,返回1表示满了,返回0表示没满
int full(char qp[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 (qp[i][j] == ' ')//棋盘上还存在空格
			{
				return 0;//棋盘没满
			}
		}
	}
	return 1;//棋盘满了
}
char win(char qp[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)//判断3行
	{
		if (qp[i][0] == qp[i][1] && qp[i][1] == qp[i][2] && qp[i][1] != ' ')//判断第几行字符相同,排除游戏开始存在的空格
		{
			return qp[i][1];//返回*就表示同一行3个字符相同--->玩家赢,返回#,P,C同理
		}
	}
	for (i = 0; i < col; i++)//判断3列
	{
		if (qp[0][i] == qp[1][i] && qp[1][i] == qp[2][i] && qp[1][i] != ' ')//判断第列行字符相同,排除游戏开始存在的空格
		{
			return qp[1][i];//返回*就表示同一行3个字符相同--->玩家赢,返回#,P,C同理
		}
	}
	//判断两个对角线
	if (qp[0][0] == qp[1][1] && qp[1][1] == qp[2][2] && qp[1][1] != ' ')
	{
		return qp[1][1];//返回* 就表示同一行3个字符相同--->玩家赢, 返回#,P,C同理
	}
	if (qp[2][0] == qp[1][1] && qp[1][1] == qp[2][2] && qp[1][1] != ' ')
	{
		return qp[1][1];//返回* 就表示同一行3个字符相同--->玩家赢, 返回#,P,C同理
	}
	//判断是否平局
	if (1 == full(qp, ROW, COL))
	{
		return 'P';//返回字符P平局
	}
	return 'C';//返回字符C游戏继续
}

       game.h:

#define ROW 3    // 3是棋盘的行数,可以随意改变数字
#define COL 3    // 3是棋盘的列数,可以随意改变数字

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

//初始化棋盘
void initqp(char qp[ROW][COL],int row,int col);//形参要小写

//打印棋盘
void displayqp(char qp[ROW][COL], int row, int col);

//玩家走
void player(char qp[ROW][COL], int row, int col);

//电脑走
void computer(char qp[ROW][COL], int row, int col);

//可以告诉我们4种状态:
//1.玩家赢   -->'*'
//2.电脑赢   -->'#'
//3.平局     -->'P'
//4.游戏继续 -->'C'
char win(char qp[ROW][COL], int row, int col);//要返回字符,所以说要用char类型返回

       test.c:

#include"game.h"//引用头文件
void menu()
{
	printf("*********************\n");
	printf("********1.play*******\n");
	printf("********0.exit*******\n");
	printf("*********************\n");
}
void game()
{
	char ret = 0;//接受返回字符,判断输赢
	char qp[ROW][COL] = { 0 };//定义棋盘时,ROW也就是行可以省,但是COL也就是列不能省,推荐大家都带上
	initqp(qp, ROW, COL);//初始化棋盘,不管之前棋盘里放了什么,全部都初始化为空格
	displayqp(qp,ROW,COL);//打印棋盘
	while (1)//无限循环下棋,直到出现下面的情况就跳出
	{
		player(qp,ROW,COL);//玩家下棋
		displayqp(qp, ROW, COL);//打印棋盘
		ret = win(qp, ROW, COL);//判断玩家是否赢了
		if (ret != 'C')//如果返回的ret不是字符c
		{
			break;//跳出循环
		}
		computer(qp, ROW, COL);//电脑下棋
		displayqp(qp, ROW, COL);//打印棋盘
		ret = win(qp, ROW, COL);//判断电脑是否赢了
		if (ret != 'C')//如果返回的ret不是字符c
		{
			break;//跳出循环
		}
	}
	if (ret == '*')//ret返回字符*
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')//ret返回字符#
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");//ret返回字符p
	}
}
int main()
{
	int n = 0;
	srand((unsigned int)time(NULL));//时间戳,用来生成随机,要引用time函数,该语句整局只用一次,所以可以放在开头处
					 //unsigned int 将time返回的值强制转化成无符号整形类型,用来作为srand随机数生成器
	do//采用do-while循环,因为玩家最少进行一次游戏
	{
		menu();//菜单函数
		scanf_s("%d", &n);//让玩家输入数字,进行选择
		switch (n)//判断玩家输入满足下面哪一个条件
		{
		case 1:
			printf("三子棋游戏:\n");
			game();
			break;//玩家输入1就打印三子棋游戏字样,并且竟然game函数进行三子棋游戏。游戏结束后自动跳出,玩家重新选择是否继续游戏
		case 0:
			printf("退出游戏");
			break;//玩家输入0,则退出游戏
		default:
			printf("输入错误,请重新输入:");//玩家如果输入1和0之外的元素,则告诉玩家输入错误,请重新输入元素
			break;
		}
	} while (n);//;不能掉
	return 0;
}

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值