三子棋(井字棋)超详细

目录

构思 

初始化棋盘

打印棋盘

玩家落子

电脑落子

 判断输赢

三子棋的胜利条件是:一行连成一线 || 一列连一线 || 对角连成一线(同样的符号)

构思 

小时候每次玩是先画棋盘,之后再由双方落子,判断输赢

因为是编写一个游戏所以不可能直接下棋(连个登出键都没有)

第一步:开始游戏(林肯死大头)

第二步:打印棋盘

第三步:   双方落子

第四步:判断输赢

接下来就开始敲代码

打印菜单

那么先打印一个开始和结束游戏的菜单

int main()
{
	int n = 0;
	printf("****************\n");
	printf("***1.开始游戏***\n");
	printf("***0.结束游戏***\n");
	printf("****************\n");
	scanf("%d", &n);
	if (n == 1)
	{
		printf("开始\n");
	}
	else if(n==0)
	{
		printf("退出游戏\n");
	}
	else
	{
		printf("请重新输入\n");
	}
	return 0;
}

这只是第一步后面还有好几步,并且还只是粗略的构思细节还没想到

都挤在主函数内显得太过臃肿,干脆直接用函数分装起来

自己创建一个头文件用来声明函数,再创建一个源文件用来定义函数,再由游戏函数来引用

创建.h文件

创建.c文件 

 

用自己的头文件用 “  ”  号来括

在游戏函数内直接调用即可,可是一个菜单在游戏开始时应该先打印一遍,并且在我玩一遍游戏后

继续玩的话直接选开始游戏,不需要再重新运行

那么这个菜单函数应该放在一个循环内且每次先打印一遍,那就要用  do while 循环了,再在循环内把菜单完善。

void ma()
{	//判断条件
	int n = 0;
	do
	{
		menu();
		printf("请选择 :");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
		{
			game();
			break;//运行完跳出
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default :
		{
			printf("\n俩选项都能选错啊!混蛋!\n");
			break;
		}

		}

	}while(n);
}

在正常选1后再进入游戏函数,选零为假退出循环

 打印棋盘

井字棋为3*3的棋盘创建一个字符二维数组就行,可里面放什么呢?打印棋盘里面就只有分隔符

只要打印了东西人看不到就行,先把数组里都放上空格。

数组的元素个数是常量,为了方便后续修改

索性就在头文件里用#define定义两个常量,后期修改只需要改这两个就都改了

 

那就在头文件中声明打印棋盘的print函数,在声明函数的文件中声明

初始化棋盘

之后才是把棋盘的分隔符给打印出来

可以把分隔符看成这样的两段组合

打印棋盘

//打印棋盘使用
	print(ch, ROW, COL);

//打印棋盘定义
void print(char arr[ROW][COL], int row, int col);

//打印棋盘声明
void print(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{//打印第一层 %c | %c | %c 
			printf(" %c ", arr[i][n]);
			if (n < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1)
		{	//打印第二层 ---|---|---
			for (int v = 0; v < row; v++)
			{
				printf("---");
				if (v < row - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

玩家落子

创建一个scan函数用来玩家输入

//打印棋盘使用
	print(ch, ROW, COL);

//打印棋盘定义
void print(char arr[ROW][COL], int row, int col);

//玩家输入定义
void scan(char arr[ROW][COL], int row, int col)
{
	printf("你的回合\n\n");
	int i = 0;
	int n = 0;
	while (1)
	{
		//死循环
		printf("请落子 :");
		scanf("%d %d", &i, &n);
		if (1 <= i && row >= i && 1 <= n && col >= n)
		{
			//由于普通玩家看到的坐标应该是从1到3所以在玩家输入后要减去1才是正确坐标
			if (arr[i - 1][n - 1] == ' ')
			{
				arr[i - 1][n - 1] = '*';
				break;//只有输入正确才会跳出
			}
			//判断是否已经有子
			else
				printf("此处已落子\n");
		}
		else//错误输入
		{
			printf("请在棋盘内落子\n");
		}
	}

}

玩家输入完毕后再把棋盘打印一遍就可以看到玩家的落子

电脑落子

也就是随机输入

随机数生成函数rand 头文件为 stdlib.h

 

 使用rand()%行或者列生成随机的二维数组下标落子

而使用它要配合srand((unsigned)time(NULL))使用time函数的参数为time_t*这里用不上所以使用

NULL空指针

srand只需要设置一次起点所以把它放在主函数开始就行

int main()
{
	//设定电脑随机值起点
	srand((unsigned)time(NULL));
	ma();
	return 0;
}

//电脑落子
		computer(ch, ROW, COL);


//电脑落子声明
void computer(char arr[ROW][COL], int row, int col);


//电脑落子定义
void computer(char arr[ROW][COL], int row, int col)
{
	//打印随机值
	printf("轮到机哥了\n\n");
	while (1)
	{	//%上row或col使随机值只能在0~2
		int i = rand() % row;
		int n = rand() % col;
		if (arr[i][n] == ' ')//判断不用多说
		{
			arr[i][n] = '#';
			break;
		}
	}

}

也是需要在落子完毕后使用print函数再打印一遍

 判断输赢

输赢使用函数就要返回一个值根据这个值判断是哪一方赢

判定条件

  1. 玩家赢返回’R'
  2. 电脑赢返回’J'
  3. 平局返回‘D'
  4. 继续下棋返回’G'

返回字符,声明一个char类型的函数

判断函数使用
h = jud(ch, ROW, COL)

//判断输赢声明
char jud(char arr[ROW][COL], int row, int col);


//创建一个只在此.c文件使用的判断平局函数
static int draw(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	//遍历
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{
			if (arr[i][n] == ' ')
			{
				//有一个空格就返回0
				return 0;
			}
		}
	}
	//遍历完后没有一个空格来到这里返回1
	return 1;
}



//判断函数定义
char jud(char arr[ROW][COL], int row, int col)
{
	//判断横向
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;//每一行初始化计数器,防止堆积
		int r = 0;
		for (n = 0; n < col; n++)
		{
			if (arr[i][n] == '#')
			{
				//计数器
				j++;
			}
			if (arr[i][n] == '*')
			{
				r++;
			}
		}
		//一行循环完毕判断计数器
		if (j == row)
		{
			return 'J';
		}
		if (r == row)
		{
			return 'R';
		}
	}
	//判断纵向
	for (i = 0; i < row; i++)
	{
		//清零
		int r = 0;
		int j = 0;
		for (n = 0; n < col; n++)
		{
			//列不动行动
			if (arr[n][i] == '*')
			{
				r++;//计数
			}
			if (arr[n][i] == '#')
			{
				j++;
			}
		}
		//判断
		if (r == col)
		{
			return 'R';
		}
		if (j == col)
		{
			return 'J';
		}
	}
	//判断正对角
	//要在循环完后判断
	int r = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		//正对角规律是行和列下标相同
		//每行只有一个
		for (n = 0; n < col; n++)
		{
			//遍历
			if (i == n)
			{
				if (arr[i][n] == '*')
				{
					//找到一个直接跳出
					r++;
				}
				if (arr[i][n] == '#')
				{
					j++;
				}
			}
		}
	}
	if (r == row)
	{
		return 'R';
	}
	if (j == row)
	{
		return 'J';
	}
	//判断反对角
	//规律是列下标是递减而行是递增刚好相反
	r = 0;
	j = 0;
	for (i = 0; i < row; i++)
	{
		if (arr[i][row - 1 - i] == '*')
		{
			//同样找到跳出
			r++;
		}
		if (arr[i][row - 1 - i] == '#')
		{
			j++;
		}
	}//判断
	if (r == row)
	{
		return 'R';
	}
	if (j == row)
	{
		return 'J';
	}
	//调用平局函数判断返回值
	if (draw(arr, row, col) == 1)
	{
		return 'D';
	}
	return 'G';
}

当然有一种简单,短的这里就不写了

更多细节尽在代码中

//游戏主文件


//三子棋 
//1.打印菜单
//2.初始化棋盘
//3.打印棋盘
//4.玩家输入
//5.电脑输入
//6.判断输赢
#include"game_1.h"//只需要引用一个头文件就ok
void game()
{
	char h = 0;
	//创建数组
	char ch[ROW][COL];
	//初始化数组为全空格
	init(ch, ROW, COL);
	//打印棋盘使用
	print(ch, ROW, COL);
	do
	{
		//玩家输入
		scan(ch, ROW, COL);
		//打印玩家落子
		print(ch, ROW, COL);
		h = jud(ch, ROW, COL);
		//电脑输入
		computer(ch, ROW, COL);
		h = jud(ch, ROW, COL);
		//打印电脑落子
		print(ch, ROW, COL);

	} while (h == 'G');
	switch (h)
	{
	case 'J':
	{
		printf("机哥赢了!细狗\n");
		break;
	}
	case 'R':
	{
		printf("你赢了。\n");
		break;
	}
	case 'D':
	{
		printf("平局,真丢脸\n");
	}
	}
}
	
	//判断玩家和电脑输赢
	/*玩家赢返回'R'
	电脑赢返回'J'
	平局返回'D'
	继续返回'G'*/
void ma()
{	//判断条件
	int n = 0;
	do
	{
		menu();
		printf("请选择 :");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
		{
			game();
			break;//运行完跳出
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default :
		{
			printf("\n俩选项都能选错啊!混蛋!\n");
			break;
		}

		}

	}while(n);
}
int main()
{
	//设定电脑随机值起点
	srand((unsigned)time(NULL));
	ma();
	return 0;
}
.h文件

//声明函数
//声明打印菜单
//把需要用的头文件都在这里敲出来其他文件使用时只需要引用此头文件就行
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>

#define ROW 3
#define COL 3

//打印菜单
void menu();
//初始化数组
void init(char arr[ROW][COL], int row, int col);
//打印棋盘定义
void print(char arr[ROW][COL], int row, int col);
//玩家输入
void scan(char arr[ROW][COL], int row, int col);
//电脑输入
void computer(char arr[ROW][COL], int row, int col);
//判断输赢
char jud(char arr[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
//定义函数
#include"game_1.h"//只需要调用一个头文件就包含了其他头文件
void menu()
{
	printf("****************\n");
	printf("***1.开始游戏***\n");
	printf("***0.结束游戏***\n");
	printf("****************\n");
}
//创建一个只在此.c文件使用的判断平局函数
static int draw(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	//遍历
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{
			if (arr[i][n] == ' ')
			{
				//有一个空格就返回0
				return 0;
			}
		}
	}
	//遍历完后没有一个空格来到这里返回1
	return 1;
}
void init(char arr[ROW][COL], int row, int col)
{
	//遍历数组全部换空格
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{
			arr[i][n] = ' ';
		}
	}
}
//打印棋盘定义
void print(char arr[ROW][COL], int row, int col)
{
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		for (n = 0; n < col; n++)
		{//打印第一层 %c | %c | %c 
			printf(" %c ", arr[i][n]);
			if (n < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1)
		{	//打印第二层 ---|---|---
			for (int v = 0; v < row; v++)
			{
				printf("---");
				if (v < row - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}
//玩家输入定义
void scan(char arr[ROW][COL], int row, int col)
{
	printf("你的回合\n\n");
	int i = 0;
	int n = 0;
	while (1)
	{
		//死循环
		printf("请落子 :");
		scanf("%d %d", &i, &n);
		if (1 <= i && row >= i && 1 <= n && col >= n)
		{
			//由于普通玩家看到的坐标应该是从1到3所以在玩家输入后要减去1才是正确坐标
			if (arr[i - 1][n - 1] == ' ')
			{
				arr[i - 1][n - 1] = '*';
				break;//只有输入正确才会跳出
			}
			//判断是否已经有子
			else
				printf("此处已落子\n");
		}
		else//错误输入
		{
			printf("请在棋盘内落子\n");
		}
	}

}
//电脑
void computer(char arr[ROW][COL], int row, int col)
{
	//打印随机值
	printf("轮到机哥了\n\n");
	while (1)
	{	//%上row或col使随机值只能在0~2
		int i = rand() % row;
		int n = rand() % col;
		if (arr[i][n] == ' ')//判断不用多说
		{
			arr[i][n] = '#';
			break;
		}
	}

}
char jud(char arr[ROW][COL], int row, int col)
{
	//判断横向
	int i = 0;
	int n = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;//每一行初始化计数器,防止堆积
		int r = 0;
		for (n = 0; n < col; n++)
		{
			if (arr[i][n] == '#')
			{
				//计数器
				j++;
			}
			if (arr[i][n] == '*')
			{
				r++;
			}
		}
		//一行循环完毕判断计数器
		if (j == row)
		{
			return 'J';
		}
		if (r == row)
		{
			return 'R';
		}
	}
	//判断纵向
	for (i = 0; i < row; i++)
	{
		//清零
		int r = 0;
		int j = 0;
		for (n = 0; n < col; n++)
		{
			//列不动行动
			if (arr[n][i] == '*')
			{
				r++;//计数
			}
			if (arr[n][i] == '#')
			{
				j++;
			}
		}
		//判断
		if (r == col)
		{
			return 'R';
		}
		if (j == col)
		{
			return 'J';
		}
	}
	//判断正对角
	//要在循环完后判断
	int r = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		//正对角规律是行和列下标相同
		//每行只有一个
		for (n = 0; n < col; n++)
		{
			//遍历
			if (i == n)
			{
				if (arr[i][n] == '*')
				{
					//找到一个直接跳出
					r++;
				}
				if (arr[i][n] == '#')
				{
					j++;
				}
			}
		}
	}
	if (r == row)
	{
		return 'R';
	}
	if (j == row)
	{
		return 'J';
	}
	//判断反对角
	//规律是列下标是递减而行是递增刚好相反
	r = 0;
	j = 0;
	for (i = 0; i < row; i++)
	{
		if (arr[i][row - 1 - i] == '*')
		{
			//同样找到跳出
			r++;
		}
		if (arr[i][row - 1 - i] == '#')
		{
			j++;
		}
	}//判断
	if (r == row)
	{
		return 'R';
	}
	if (j == row)
	{
		return 'J';
	}
	//调用平局函数判断返回值
	if (draw(arr, row, col) == 1)
	{
		return 'D';
	}
	return 'G';
}

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值