【保姆级】你真的会做三子棋吗? (C语言基础版)数组+函数

大家好,今天要讲的是三子棋,大家小时候应该都玩过吧,今天我来教大家如何用C语言来做游戏。

首先,要把代码进行模块化分组。

像这样:

为什么要这样做呢?

第一、有利于处理代码,让代码看起来不那么冗长复杂。

第二、模块化有利于让你更好的调试代码,发现代码的问题。

(悄悄告诉你:很多大厂程序员都在用哦!!!)

好,接下来,进入正题:

下棋首先要有什么?

OS:要有棋子

其实要先打印菜单了,然后在打印棋盘,确定棋子,判断输赢等等。

让我们一步一步来看看吧。

这是一个游戏小菜单,1是玩游戏,0是退出

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

好了接下来要把它放到主函数里面去调用它(test.c)

int main()
{
	int input = 0;
	do
	{
		menu();//这里是调用上面的menu函数
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//这里是游戏的具体实现
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	return 0;
}

讲解一下:看到这么多代码不要慌,这里都是一些很基础的东西,都是大家的老朋友了。

第一步:把主函数和return 0的框架写出来,如果不会写去baidu查一下Hello World,然后要定义并初始化一个input,接收输入的数字;

第二步:用do——while,并把刚刚写好的(菜单)menu函数调用一下,加上一个printf函数,提醒我们选择0或1,并用scanf输入,input接收;

第三步:在do——while里面我们要用switch语句,case 1就是输入1进行游戏,case 0就是退出游戏,default代表输入的数字不是0和1,所以我们要用printf提醒别人,让他重新输入。break是跳出当前循环。

第四步:如果玩完了还想再来一次怎么办?所以在do和while的括号里放入了input,这样的话,input的为真,就会一直循环,直到input为假。

tips:在C语言中0为假,非0为真。

菜单做好了,接下来我们继续

1.棋盘(test.c)

void game()
{
    //创建棋盘
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
}

game.h

#define ROW 3
#define COL 3

//初始化棋盘

void Initboard(char board[ROW][COL], int row, int col);

//打印棋盘

void Displayboard(char board[ROW][COL], int row, int col);

game.c

void Initboard(char board[ROW][COL], int row, int col)
{
	int m = 0;
	int n = 0;
	for (m = 0; m < row; m++)
	{
		for (n = 0; n < col; n++)
		{
			board[m][n] = ' ';
		}
	}
}


void Displayboard(char board[ROW][COL], int row, int col)
{
	int m = 0;
	for (m = 0; m < row; m++)
	{
		int n = 0;
		for (n = 0; n < col; n++)
		{
			printf(" %c ", board[m][n]);
			if (n < col - 1)
				printf("|");
		}
		printf("\n");

		if (m < row - 1)
		{
			int n = 0;
			for (n = 0; n < row; n++)
			{
				printf("---");
				if (n < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}

这里一共三个步骤:

第一步:创建棋盘,定义一个二维数组board,然后我们要在game.h中定义二维数组的行和列,行为ROW,列为COL。

第二步:初始化棋盘,我们用Initboard进行初始化棋盘,返回类型为void,小写的row和col是Initboard函数的形参。在game.h中声明函数,我们需要把函数拿到game.c中实现。很简单,定义两个变量,两层for循环,让我们的的棋盘初始化为空格。第一层for循环,m初始化后,开始和我们的行比较,比较后使用,再加1循环。第二次循环一样,不过是列的循环。

第三步:打印棋盘,由于我们要看到棋盘,所以需要把棋盘打印出来,用返回值为void的Displayboard函数实现。同样把它放到game.h中声明一下,在game.c中具体实现。

具体细节:同样是用for循环,我们先看元素的打印,前面就两层for循环确定位置,打印的东西很重要哦,我用了空格+%c+空格的方式打印行上的元素,然后用|分隔开,但是这个|是有条件的,最后那一列不打印,最后再换个行,这样看起来就比较美观。然后是分隔符的打印,这个就比较简单了,一个for循环遍历行打印分隔符,再加上一个if函数判断一下,打印|保持一致,最后换个行,完美。

这里我们完成了棋盘,接下来我们要开始下棋了 :

和上面一样,我们要用函数的方式进行。

我们先想出函数的功能,再去实现函数(test.c)

void game()
{
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	//下棋
	while (1)
	{

		PlayerMove(board, ROW, COL);//玩家下棋
		
		
		Displayboard(board, ROW, COL);//打印棋盘


		ComputerMove(board, ROW, COL);//电脑下棋
	
		
		Displayboard(board, ROW, COL);//打印棋盘
	}



int main()
{
	srand((unsigned int)time(NULL));//随机数设置


	int input = 0;
	do
	{
		menu();
		printf("请选择:>");

		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);

	return 0;
}

函数声明(game.h)

void PlayerMove(char board[ROW][COL], int row, int col);

void ComputerMove(char board[ROW][COL], int row, int col);

函数功能实现(game.c)

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d%d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,不能下棋\n");
			}
		}
		else
			printf("坐标非法,请重新输入!\n");
	}
}


void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	int x = 0;
	int y = 0;

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

我这里主要写了玩家和电脑对弈的代码,所以比较简单,但是有不少细节,我来讲解一下:

这里也是分为三个步骤:

第一步:玩家下棋:我们定义一个PlayerMove来实现,把棋盘,行和列的信息传给它并声明一下。由于数组的下标是从0到1的,我们新定义一个X和一个Y放到while(1)循环,然后我们用if判断限制输入,重点来了,因为玩家不一定知道数组的知识,所以我在这里把x和y从1开始,然后再来一个if把x-1和y-1放入判断是否为空格,是空格就可以下,下完就break,不是空格就提示,然后重新循环,如果输入坐标不在第一个if判断的范围,提示坐标非法,重新循环。

第二步:电脑下棋:我们定义一个ComputerMove来实现,把棋盘,行和列的信息传给它并声明一下。电脑下棋很简单,直接一个if判断x和y放进去判断不是空格就行。细心的小伙伴发现,这里有个rand是什么意思啊?大家注意,这个rand是随机数的意思,它的范围是0到rand_max(32767)。然后有个设置它的东西叫srand,你们可以看到我在主函数中写出来了,那这个time又是什么意思呢?time是时间戳,我们让它返回一个空指针,然后再强制类型转换成(无符号整型)。rand % row和rand % col是让电脑取随机再0-2之间,避免数组越界。

第三步:测试!测试!测试!玩家下棋用*表示,电脑下棋用#表示,我们第三步要测试一下,我们能不能正常下棋,如果不能正常下棋,要确定是不是if条件出问题了或者是数组越界了。这是最重要的一步,任何人都会写出bug,不用慌张,要仔细去检查,然后在总结,下次就不会再次出现bug了,这样不断反复,慢慢自己就会变强。

好了,到这里,我们基本完成了80%以上,但是还有一个步骤,那就是判断输赢的过程:

这里我规定了一下: 玩家赢————‘*‘         电脑赢————‘#’     平局————’Q‘         游戏继续————‘C’

上面的值大家都可以修改,只要你愿意设置什么样的就设置什么样的,这只是我这个代码的思路。

 同样我用了函数来帮助我实现(test.c)

void game()
{
	char win = 0;

	char board[ROW][COL] = { 0 };

	//初始化棋盘

	Initboard(board, ROW, COL);

	//打印棋盘

	Displayboard(board, ROW, COL);

	//下棋

	while (1)
	{

		PlayerMove(board, ROW, COL);

		win = Iswin(board, ROW, COL);

        //判断输赢

		if (win != 'C')
		{
			break;
		}

		Displayboard(board, ROW, COL);

		ComputerMove(board, ROW, COL);

		win = Iswin(board, ROW, COL);

        //判断输赢

		if (win != 'C')
		{
			break;
		}
		Displayboard(board, ROW, COL);
	}

	if (win == '*')
	{
		printf("玩家赢\n");

		Displayboard(board, ROW, COL);
	}
	
    else if (win == '#')
	{
		printf("电脑赢\n");

		Displayboard(board, ROW, COL);
	}

	else
	{
		printf("平局\n");

		Displayboard(board, ROW, COL);
	}
}

函数声明(game.h)

int IsFull(char board[ROW][COL], int row, int col);

char Iswin(char board[ROW][COL], int row, int col);

函数实现(game.c)

int IsFull(char board[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 (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}


char Iswin(char board[ROW][COL], int row, int col)
{

	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}

	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

这里同样我分三个步骤讲解:

第一步:我们用正常逻辑思考,玩家下完棋要不要判断输赢,电脑下完棋要不要判断输赢,要是吧。所以我先用if判断整个棋盘能不能继续下棋,如果不能我们跳出while(1),来到我们下面的第二个if,如果是*就算玩家赢了,是#就算电脑赢了,如果都不是,那我们刚刚判断过了游戏不能继续,所以只能是平局。好了,这是第一步。

第二步:我在test.c里有两个函数没有实现,一个是IsWin和IsFull,好我们在game.c中实现一下。

首先IsFull,两层for循环遍历元素,if判断是否有空格,有空格棋盘没满返回0,没有空格就是棋盘满了返回1,返回类型int。其次是IsWin,三子棋赢的规则就是三个棋子连在一起就赢了,所以我们分为行,列,对角线三种情况,首先分析行,一个for循环表示行号,然后加上if判断,这判断条件很有意思,首先是第i行的三个元素两两相等,啪,有的同学写到这里就完了,注意啊,这里要加上不能等于空格!!! 不然永远都是你赢!!!返回值当然是第i行上的任意一个元素了。

第三步:好了,行写完,列的也差不多,for循环表示列号,加上if判断,第i列的三个元素两两相等,然后一样不等于空格。接下来是对角线,对角线有两条,一样是 对角线上的元素两两相等,然后不等于空格。最后,如果都判断完了 ,三种情况都没人赢,那再判断一下IsFull是否等于1,如果等于,那就是平局返回Q,如果不是就返回C

注意:细心的小伙伴肯定发现,我这里行和列,对角线的判断输赢写成了固定的3行3列了,如果想写成N字棋的话,把这块改一下,我相信这对于评论区的前排来说还是很简单的。

好了,到这里,我们全部的代码就大功告成了,其实编程也不是很难,对不对?

接下来把代码整合一下:

(test.c)

#include "game.h"
void menu()
{
	printf("*****************************************\n");
	printf("*************** 1 . play ****************\n");
	printf("*************** 0 . exit ****************\n");
	printf("*****************************************\n");
}
void game()
{
	char win = 0;
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	//下棋
	while (1)
	{

		PlayerMove(board, ROW, COL);
		win = Iswin(board, ROW, COL);//判断输赢
		if (win != 'C')
		{
			break;
		}
		Displayboard(board, ROW, COL);

		ComputerMove(board, ROW, COL);
		win = Iswin(board, ROW, COL);//判断输赢
		if (win != 'C')
		{
			break;
		}
		Displayboard(board, ROW, COL);
	}


	if (win == '*')
	{
		printf("玩家赢\n");
		Displayboard(board, ROW, COL);
	}
	else if (win == '#')
	{
		printf("电脑赢\n");
		Displayboard(board, ROW, COL);
	}
	else
	{
		printf("平局\n");
		Displayboard(board, ROW, COL);
	}
}

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	return 0;
}

函数声明(game.h)

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


#define ROW 3
#define COL 3

//初始化棋盘

void Initboard(char board[ROW][COL], int row, int col);

//打印棋盘

void Displayboard(char board[ROW][COL], int row, int col);

void PlayerMove(char board[ROW][COL], int row, int col);

void ComputerMove(char board[ROW][COL], int row, int col);

int IsFull(char board[ROW][COL], int row, int col);

char Iswin(char board[ROW][COL], int row, int col);

game.c

#include "game.h"

void Initboard(char board[ROW][COL], int row, int col)
{
	int m = 0;
	int n = 0;
	for (m = 0; m < row; m++)
	{
		for (n = 0; n < col; n++)
		{
			board[m][n] = ' ';
		}
	}
}

void Displayboard(char board[ROW][COL], int row, int col)
{
	int m = 0;
	for (m = 0; m < row; m++)
	{
		int n = 0;
		for (n = 0; n < col; n++)
		{
			printf(" %c ", board[m][n]);
			if (n < col - 1)
				printf("|");
		}
		printf("\n");

		if (m < row - 1)
		{
			int n = 0;
			for (n = 0; n < row; n++)
			{
				printf("---");
				if (n < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d%d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,不能下棋\n");
			}
		}
		else
			printf("坐标非法,请重新输入!\n");
	}
}


void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	int x = 0;
	int y = 0;

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}




int IsFull(char board[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 (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}


char Iswin(char board[ROW][COL], int row, int col)
{

	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}

	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

最后说明一下啊,我把所有的头文件放在了game.h里面,这样只要引头文件game.h就行,time函数要<time.h>,printf函数尧<stdio.h>,rand函数要<stdlib.h>。

感谢大家的观看,后期我会分析一些基础C语言的干货知识(太忙了,555)。

如果大家喜欢,点上关注不迷路。有错误一定要告诉我,我会很开心的,谢谢大家。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值