C语言----小游戏三子棋-创新互联

相信大家或多或少都听说过五子棋,三子棋也是类似,即达成每行或每列中有三颗连续棋子,亦或是在对角线上有三颗连续的棋子即为胜利。今天,我们就来实现一下。

目前创新互联建站已为1000多家的企业提供了网站建设、域名、虚拟主机成都网站托管、企业网站设计、安岳网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

目录

一、文件的准备

二、功能的实现

1.菜单与用户的选择

2.游戏的函数

3.棋盘的初始化

4.打印棋盘

5.下棋->玩家下棋

6.下棋->电脑下棋

7.判断结果

a.当一行中三个相等时

b.当一列中三个相等时

c.当对角线上相等时

d.判断平局

8.程序补全


一、文件的准备

为了后期代码的封装,我们将测试代码,函数代码和函数的声明分开存放到不同的文件中。如下:

test.c        ——        用于存放测试游戏功能实现的代码

game.c     ——        用于存放游戏相关的函数的具体内容

game.h      ——        用于存放游戏中功能函数的声明以及相关类型的定义

为了便于区分,将在后文的代码演示处首行以注释方式写明所属文件。

二、功能的实现         1.菜单与用户的选择

市面上的游戏的选项有很多,我们只完成最基础的玩游戏和退出。

我们创建无返回值的menu作为菜单,由于只用来测试,写在test.c中。

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

为了使用户有较好的游戏体验,我们使用循环来判断,只有当用户选择退出游戏才会退出,选择的不是玩游戏或者退出就提示错误并重新输入。

// test.c
int main()
{
	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;
}
2.游戏的函数

当用户输入1选择进入游戏后,就需要进入具体的游戏程序中,我们在play的选项后创建Game函数用来存放游戏代码。Game的使用在上文的代码段中已有体现,接下来只讲声明与定义。

我们将Game函数也存放在test.c中,基础代码如下:

// test.c
void Game()
{
	char board[ROW][COL] = { 0 };

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);

	...

}

下棋,必不可少的就是棋盘。

我们创建一个二维数组来存放棋盘,棋盘的大小就设定为3X3,在二维数组中即为每行3个元素,共3行。

为了方便后期代码的维护,我们使用#define自定义行和列,并存放在我们编写的game.h中,方便调用。

// game.h

#include#include#include#include#define ROW 3
#define COL3

为了方便,已经后文需要引用的头文件一起添加,后文有关内容将仅做提示。

特别注意:由于自定义类型在别的文件中需要引用,也为了减少代码内容,另外两个.c需要引用头文件game.h,如下:

// test.c        game.c
#include "game.h"

创建字符类型二维数组board作为棋盘,行和列分别使用已定义的ROW和COL,Game函数中已有体现。

3.棋盘的初始化

在开始下棋之前,需要先清理棋盘,程序中也是一样,我们需要对棋盘进行初始化,创建InitBoard用于实现初始化。

由于自此之后绝大部分函数都涉及到具体的游戏内功能,故函数的使用均在Game函数中,有使用方式特别的会单独指出;函数的声明存放到头文件game.h中;函数的具体内容存放到game.c中,在此仅作演示,之后的声明和定义将省略。

声明:

// game.h
void InitBoard(char board[ROW][COL], int row, int col);

定义:

// game.c
void InitBoard(char board[ROW][COL], int row, int col)
{
	;
}

具体的内容在之后会有体现。

我们将棋盘上的落棋点,也就是二维数组中的元素初始化为空格字符,即' ',可以使用嵌套的for循环来实现,具体如下:

// game.c
void InitBoard(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++)
		    {
			    board[i][j] = ' ';
		    }
	    }
}
4.打印棋盘

在下棋之前,必须要能看到棋盘的内容,所以在初始化后就需要打印出来,方便观察。

都初始化为空格,直接打印肯定不方便观察,而且下棋也需要使用其他符号作为每个格子的分界,我们使用“-”和”|“作为分界,且分隔符与单元格并不是一一对应,而是只在两个各自之间才需要分割,所以循环的条件就是行数/列数 减去1,这里类似于数组元素和下标的关系。

代码如下:

// contact.c

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i< row; i++)
	{
		int j = 0;
		for (j = 0; j< col; j++)
		{
			printf(" %c ", board[i][j]);
			if(j

打印出来的棋盘样式如图:

5.下棋->玩家下棋

我们创建PlayMove函数用作玩家下棋,并将玩家可以出的棋子定义为'*':

给出玩家下棋的提示,使用printf打印。

在二维数组中行和列的下标均是从0开始,但是玩家并不一定知道下标这个概念,进而输入为从1开始的任意数值,我们就需要判断输入玩家输入的坐标是否在现有的棋盘内,使用if判断,由于有多个条件,我们使用C语言逻辑运算符中的与&&连接判断条件。

程序设计为人机对战,当用户输入的坐标是处于棋盘上的时候,我们还需要对所输入的坐标是否已有用户或者电脑使用过此坐标。若为我们初始化的' '就是没有被使用过,就将'*'置入该坐标中。代码如下:

// 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");
		}
	}
}
6.下棋->电脑下棋

我们创建ComMove函数来表示电脑下棋,使用'#'作为电脑所下的棋子:

电脑下棋无法像玩家一样输入自己要下的,我们需要使用随机数来获取行和列。

C语言中,一般使用rand()函数来生成随机数,但随机数的范围太大,且多次连续运行时产生的结果相近或为统一结果,不适用于直接生成想要的随机数。

我们使用srand()函数对随机范围进行指定,在srand中则使用time函数获取每时每刻都在变化的时间(精确到秒)。

用获取得到的随机数在求与行/列的模,求出的随机数即在二维数组的范围内,只需判断所随机得到的坐标是否有棋子即可,为空表示可以将棋子落下,有内容则重新进行随机。

关于time函数仅作使用,不做过多描述,可自行查阅。

srand即为以下内容:

// test.c
srand((unsigned int)time(NULL));

rand函数需要引用头文件,time函数需要引用头文件

函数内容如下:

// game.c
void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>\n");

	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
7.判断结果

是比赛就有胜利、失败以及平局。

三子棋中当一方棋子连成三点一线(包括对角线)时,即为胜利,另一方失败;

当棋盘下满仍无三颗同一方棋子连线时,即为平局

我们创建IsFull函数用来判断期盼是否已满,并返回1或0作为满或未满。

只需要对二维数组进行遍历,逐个判断是否为' ',即可确定棋盘是否已满。

如下:

// 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;
}

然后就是判断棋盘上的棋子是否有一方满足胜利条件,创建IsWin函数来进行判断

a.当一行中三个相等时

使用for循环判断当棋盘中行数不变时,每一列的格子内的棋子都相同且不为空时,就返回相同的那种棋子;

b.当一列中三个相等时

与上一种判定方法类似,不同之处在于列不变,每一行相同且不为空,返回相同的棋子

c.当对角线上相等时

对角线相同有两种情况,一种是从左上到右下,即[0][0],[1][1],[2][2]相同且不为空;另一种是从右上到左下,即[0][2],[1][1],[2][0]相同且不为空。两种情况满足一种即返回相同的棋子。这里同样使用逻辑或&&对判断条件进行连接

d.判断平局

在创建判断棋盘是否已满的函数时,我们定义为了int类型,设定了返回值为0或1,在IsWin中,我们创建变量ret对IsFull的结果进行判断,若为1(表示棋盘已满)就返回'D',表示平局;若为0(棋盘未满)就返回'N'

函数代码如下:

// game.c
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 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 (i = 0; i< col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}
	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];
	}

	int ret = IsFull(board, row, col);
	if (ret == 1)
	{
		return 'D';
	}
	return 'N';
}
8.程序补全

函数的功能和定义已经完成,接下来回到测试文件对逻辑进行补全。

下棋需要多次的玩家和电脑进行落子,故使用while循环进行轮流下棋,逐步显示当前棋盘的内容并判断是否满足胜利或者平局,有一方胜利或者棋盘已满便退出循环,不再落子。

然后就可以对返回值进行判断:

     如果返回的是表示玩家的棋子'*',就输出玩家胜利并打印棋盘;

     如果返回的是表示电脑的棋子'#',就打印电脑胜利并打印棋盘;

     若返回其他内容则表示棋盘已满,打印平局并打印棋盘。

代码如下:

// test.c
void Game()
{
	// 一个存放棋盘的3x3的二维数组
	char board[ROW][COL] = { 0 };
	// 初始化棋盘
	InitBoard(board, ROW, COL);

	// 打印棋盘
	PrintBoard(board, ROW, COL);

	char ret = 0;

	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//判断玩家是否赢得游戏
		ret = IsWin(board, ROW, COL);
		if (ret != 'N')
			break;
		//电脑下棋
		ComMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		//判断电脑是否赢得游戏
		ret = IsWin(board, ROW, COL);
		if (ret != 'N')
			break;
	}
	if (ret == '*')
	{
		printf("玩家赢了\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢了\n");
	}
	else
	{
		printf("平局\n");
	}
	PrintBoard(board, ROW, COL);
}

至此,简单的三子棋游戏已经完成,具体的代码文件已上传,可点击下方链接进行查看:

GitCode-shiwuqing-game1

Gitee-shiwuqing-game1

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧

文章题目:C语言----小游戏三子棋-创新互联
网址分享:https://www.cdcxhl.com/article42/ddddhc.html

成都网站建设公司_创新互联,为您提供标签优化企业网站制作营销型网站建设微信公众号微信小程序网站营销

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联