【无标题】用c语言数组实现三子棋(学到数组即可实现)

1.规则了解:

2.游戏程序预分析

3.设计游戏

1规则了解:

想必大家都知道,三子棋是互相各下一子,谁先在对角线,平行线方向连成三个连续相同的子谁就赢得胜利.

2游戏程序分析:

结合规则可知,我们要实现三子棋,首先得有个菜单,让玩家选择是否玩,随后就进入了我们的游戏程序模块,在这个模块中,第一步我认为是得先有个棋盘,这个棋盘可以显示我们的下棋情况,这时候才到我们真正下棋,大致代码思路理清了,接下来我们就开始设计游戏,并逐渐补充代码模块。提炼如下:

(1)打印菜单

(2)打印棋盘

(3)下棋

3:设计游戏

第一步写出主函数,这个主函数放在源.c文件,我们需要一个变量a,用来接收用户选择是否玩游戏,1是玩,0是退出,为了简便,我们用switch语句来写出1和0的分支,并用default字句应对用户输入非1非零的情况,我们希望这个游戏可以反复的玩,也就是我们可以多次选择是否玩游戏,并且至少要用户选择一次,很明显用do while,这个循环是否结束就恰好可以用变量a的值,此时可见a的定义放在循环外,放在内部定义a不可以作为循环判断条件。

void menu()
{
	printf("*******1.play  *************\n");
	printf("*******0.exit  *************\n");
}
int main()
{
	int a = 0;
	do
	{
		//打印菜单
		menu();
		//接收选择
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("请重新输入\n");
		}
	} while (a);
	return 0;
}

第二步:

用户选择一,我们进入玩游戏的程序game()函数,(我们在设计时将游戏功能实现函数如判断输赢函数,玩家电脑下棋函数放在game.c文件,这些函数的申明放在game.h这个头文件)这时我们打印出棋盘,让用户下棋,我们得想想这个棋盘对应C语言的什么,是什么能储存我们在下子时的那个记号,比如*和#,并且是我们输入坐标它就能存储到相应位置并且打印显示,那这不就是二维数组嘛,二维数组虽然是连续存放的,但我们也可以理解为是一个正方形表格,我们打印这个表格元素的时候加上框框不就是我们的棋盘嘛。上代码!先用自定义函数initial把棋盘扫干净。再用自定义函数Printf打印棋盘。

void initial(char arr[Row][Line], int row, int line)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{
			arr[i][j] =' ';
		}
	}
}
void Printf(char arr[Row][Line], int row, int line)
{
	int cou = 0;
	int i = 0;
	for (i=0;i<row;i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{  
			printf(" %c ",arr[i][j]);
			if(j<line-1)
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < line; j++)
			{
				printf("___");
				if (j < line - 1)
					printf("|");
			}
		}
		printf("\n");
	}
}

这些函数都涉及到了对二维数组的传参,奈何本人知识有限,我只能说二维数组传参格式之一就是这样,行列大小也要上传,Row,Line是我在game.h这个头文件用宏定义的标识符常量,便于我们以后将三子棋优化为n子棋时对代码的改写。我们把数组元素和边框' | '作为作为一组打印,循环一次打印一组,此外,打印’ | '是if控制的,所以打印第三组的时候‘ | ’未打印出来,构造成一个半开半闭的格子,内层循环结束第一层打印完毕,而这样的格子数目等于数组列数,所以内层循环结束的标志,就是小于列数line,因为0到line的数字个数等于line,这个想必大家知道吧。

 

 然后我们再用下面这个内层循环打印‘——  |‘,结束与上一个内层循环一样,只是打印元素有差别,我们注意到这个循环是用if(i<row-1)控制的,这使得'——  |'这种的只有两层,

if (i < row - 1)
		{
			for (j = 0; j < line; j++)
			{
				printf("___");
				if (j < line - 1)
					printf("|");
			}
		}
		printf("\n");

 此时我们终于到了下棋,首先是我们下棋,调用player_move函数,我们先输入坐标,这个坐标和计算机看到的是不一样的,比如在棋盘我们认为是第一行第一列,而在数组中它则[0][0]号元素,所以我们要将坐标减1,才能转换为在数组的位置 。

我们输入了一个坐标还需要不停地判断这个坐标是否被占用,以及是否在数组内,直到玩家输入的坐标是合法的,我们此时才能跳出循环,一次下棋结束。

void player_move(char arr[Row][Line], int row, int line)//玩家下棋
{
	int x = 0; 
	int y = 0;
	while (1)
	{
		printf("玩家请输入坐标\n");
		scanf_s("%d %d", &x, &y);
		if (x <= row && y <= line && x >= 1 && y >= 1)
		{
			
			if (arr[x - 1][y - 1] == ' ')
			{
				printf("坐标合法,下棋成功\n");
				arr[x - 1][y - 1] = '*';//玩家下棋标志为*
				break;
			}
			else
				printf("坐标被占用,请重新输入\n");
		}
		else
			printf("坐标非法请重新输入\n");
	}
}

接下来就是电脑下棋,此时我们只需要让电脑随机在一个空的棋盘格子处下棋,这就涉及到了两个步骤,第一:产生一个随机数,第二找到一个空位置。所以我们还是用一个死循环,而获取一个随机数则用rand()函数,这个函数的头文件为<stdlib.h>,还要设置一次随机数生成起点,就是在主函数中调用一次srand((unsigned int )time(NULL)),将随机数用%取模,我们得到的数就可以直接转换为坐标,之后就是用If判断该位置是否是空的,是空的就把此处的赋成电脑下棋标志‘#’。

void computer_move(char arr[Row][Line], int row, int line)
{
	while (1)
	{
		int x = rand() % row;
		int y = rand() %line;
		if (arr[x ][y ] == ' ')
		{
			arr[x ][y ] = '#';//电脑下棋标志为#
			break;
		}
	}
}

此时我们已经把双方下棋的代码编写好了,那是不是还要有能判断胜负的函数,在3乘3的棋盘上我们每次下棋之后只会出现玩家赢返回‘*’,电脑赢返回‘#’,平局返回‘Q’(棋盘满了同样也要结束游戏,不然我上面那么多个死循环就会因为找不到空位而无法结束),以及游戏继续返回'C'这四种情况,赢得标志是行相等,列相等,或者两条斜线相等

行相等:

int i = 0;//判断行相等
	for (i = 0; i < row; i++)
	{
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2]&&arr[i][0]!=' ')
			return arr[i][0];
	}

列相等:

int j = 0;//判断列相等
	for (j = 0; j < line; j++)
	{
		if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
			return arr[0][j];

    }

斜线相等:

//判断斜线相等
	if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2]&&arr[0][0]!=' ')
		return arr[0][0];
	if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0]&&arr[0][2]!=' ')
		return arr[0][2];

在此我们可以看到我们返回的是数组中出现行相等,列相等的元素,而没有这是为了这个函数的可移性变好,不然我们得给玩家和电脑各自编写一个判断胜负函数,显得十分啰嗦,还不如直接返回满足胜条件的元素,再来判断这个返回值是什么来判断谁赢了。

还有判断棋盘是否满了:

char is_full(char arr[Row][Line], int row, int line)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{
			if (arr[i][j] == ' ')
				return 'C';
			
		}
	}
	return 'Q';
}

完整代码:

源.c

#include"game.h"
void menu()
{
	printf("*******1.play  *************\n");
	printf("*******0.exit  *************\n");
}
void game()
{
	//打印棋盘,棋盘存放落子情况
	char arr[Row][Line];//三字棋,大小为三行三列
	//初始化棋盘
	initial(arr,Row,Line);
	//打印棋盘
	Printf(arr, Row,Line);
	char win = 0;
	while (1)
	{   //玩家下棋
		player_move(arr, Row, Line);
		//打印玩家下棋结果
		Printf(arr, Row, Line);
		//判断输赢
		 win = is_win(arr, Row, Line);//玩家赢,返回*
		if ( win!='C')
			break;
		//电脑下棋
		computer_move(arr, Row, Line);
		//打印电脑下棋结果
		Printf(arr, Row, Line);
		win = is_win(arr, Row, Line);//电脑赢,返回#   游戏继续返回C  平局返回Q
		if (win!='C')
			break;
	}	
	if ('*' == win)
	{
		printf("玩家赢\n");
	}
	else if ('#' == win)
	{
		printf("电脑赢\n");
	}
	else if ('Q' == win)
	{
		printf("平局\n");
	}
}
int main()
{
	int a = 0;
	srand((unsigned int )time(NULL));
	do
	{
		//打印菜单
		menu();
		//接收选择
		scanf_s("%d", &a);
		switch (a)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("请重新输入\n");
		}
	} while (a);
	return 0;
}

game.h

#define Row 3 //“宏定义两个变量的写法”
#define Line 3
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
void initial(char arr[Row][Line], int row, int line);//“注意二维数组的传参”
void Printf(char arr[Row][Line], int row, int line);//打印棋盘
void player_move(char arr[Row][Line], int row, int line);//玩家下棋
void computer_move(char arr[Row][Line], int row, int line);//电脑下棋
char is_win(char aarr[Row][Line], int row, int line);//判断输赢

game.c

#include"game.h"
char is_full(char arr[Row][Line], int row, int line)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{
			if (arr[i][j] == ' ')
				return 'C';
			
		}
	}
	return 'Q';
}
void initial(char arr[Row][Line], int row, int line)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{
			arr[i][j] =' ';
		}
	}
}
void Printf(char arr[Row][Line], int row, int line)
{
	int cou = 0;
	int i = 0;
	for (i=0;i<row;i++)
	{
		int j = 0;
		for (j = 0; j < line; j++)
		{  
			printf(" %c ",arr[i][j]);
			if(j<line-1)
				printf("|");

		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < line; j++)
			{
				printf("___");
				if (j < line - 1)
					printf("|");

			}
		}
		printf("\n");
	}
}
void player_move(char arr[Row][Line], int row, int line)//玩家下棋
{
	int x = 0; 
	int y = 0;
	while (1)
	{
		printf("玩家请输入坐标\n");
		scanf_s("%d %d", &x, &y);
		if (x <= row && y <= line && x >= 1 && y >= 1)
		{
			
			if (arr[x - 1][y - 1] == ' ')
			{
				printf("坐标合法,下棋成功\n");
				arr[x - 1][y - 1] = '*';//玩家下棋标志为*
				break;
			}
			else
				printf("坐标被占用,请重新输入\n");
		}
		else
			printf("坐标非法请重新输入\n");
	}
}
void computer_move(char arr[Row][Line], int row, int line)
{
	while (1)
	{
		int x = rand() % row;
		int y = rand() %line;
		if (arr[x ][y ] == ' ')
		{

最后,在这个代码中我有一个点没有给读者讲清,比如随机数函数的使用,因为我的代码不好测试这个函数的使用规范,读者们可以看个猜数字游戏的博客看看这个函数是如何使用的,还有就是我为什么要把主函数放在源.c文件,而游戏具体函数实现放在game.c,这些函数声名则放在game.h中,好处如下一:随着我们技术的提升,我们要实现的功能只会越来越多,总不能都在主函数定义函数,那不就十几个人共用一台电脑(想想那场面,后面的程序员催促说,写完没啊,快点啊,到我写了,真是有点哭笑不得)。二:有利于我们隐藏我们的源码,这点就不展开说啦,好啦,一不小心就写了近六千多,我真不想写这么长,因为我一开始逛csdn的时候看到长文章就晕,我也不想别人看到我的文章也晕,我已经在尽量减少字数了,实在是代码有时候真是一环扣一环,不好省略,如果读者是比我还萌的萌新就看看我的思路,自己尝试写一写,卡壳再来看看完整代码,是大佬的话读者自便哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小何只露尖尖角

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值