c语言实现三子棋小游戏

欢迎来到程序员的快乐!

目录

一、游戏规则:

二、编程准备和分析:

三、游戏菜单界面打印

 四、创建字符数组存储数据

五、初始化棋盘

六、棋盘打印

 七、玩家1,玩家2轮流下棋

 八、判断游戏胜出、平局、继续

九、、游戏测试 

十、总体代码:



 

一、游戏规则:

       两位玩家进行博弈,棋盘为3*3,当一方玩家的3个棋子连成一条线的时候胜利。如果棋盘上没有落子的位置且没有玩家胜出的时候判定为平局。

二、编程准备和分析:

1、准备

c语言实现三子棋小游戏_第1张图片

game.h:游戏相关的函数声明,头文件包含,符号声明。

text.c:测试游戏的逻辑。

game.c:游戏相关函数的实现。

2、分析:

可能出现的四种游戏状态:玩家1胜、出玩家2胜、平局、游戏继续。

可能不是很熟悉的语法:#define  定义的标识符常量。

三、游戏菜单界面打印

1、自己动手来给三子棋写一个menu()函数实现菜单界面的打印。

void menu()
{
	printf("----------- Tic-Tac-Toe -----------\n");
	printf("*********** 1.开始游戏 ************\n");
	printf("*********** 0.退出游戏 ************\n");
	printf("-----------------------------------\n");
	
}

2、在主函数中使用do...while循环语句和switch多分支语句选择不同选项出现不同效果,我们暂时输出一句话来展现不同的效果。input是我们定义的一个变量,并把它当做循环和分支的条件表达式,当input = 1时开始游戏,input = 0 时退出游戏并且退出循环,input= 其它值时打印出一句错误提醒!

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入选项:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("游戏开始!\n");
			break;
		case 0:
			printf("退出游戏!\n");
			break;

		default:
			printf("选项错误,请重新输入:");
		}
		printf("\n");
	} while (input);
	
	
	return 0;
}

3、效果展示:

c语言实现三子棋小游戏_第2张图片

 四、创建字符数组存储数据

1、首先,我们写一个game()函数来实现游戏的一些逻辑!游戏界面打印好后,就要在game()函数中(在上述case 1:调用game()这个函数!)搭建游戏场景。第一步我们创建一个字符数组来存储数据,因为三子棋的棋盘是3*3,所以我们可以写成:

 char board[3][3];

这样写是没有问题的,但是对于程序员来说,我们要考虑到代码的耦合度,假设我们突然想要把棋盘改成5*5或者更大的棋盘,就要改动大量的代码,这时候我们的效率就大大降低,而且更容易出错!综上所述,我们可以对代码进行这样的优化:

2、在game.h中定义标识符常量行(ROW)和列(COL)

//符号的定义
#define ROW 3//表示行
#define COL 3//表示列

注意:在Text.c中写上头文件#include "game.h"

3、这时我们就可以写成这样:

 char board[ROW][COL];

到这里我们就完成了数组的创建! 

五、初始化棋盘

实际上就是对数组的初始化,在game()函数中调用一个用来初始化的函数initboard(board, ROW, COL);,传入的3个参数分别是二维数组、行、列

把这个和游戏相关的函数写在game.c中:

//初始化棋盘
void initboard (char ch[ROW][COL],int row,int col)
{
	//遍历二维数组
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			ch[i][j] = ' ';
		}
	}
}

六、棋盘打印

在game()函数中调用一个用来打印棋盘的函数printfboard(board, ROW, COL);传入的3个参数分别是二维数组、行、列

把这个和游戏相关的函数写在game.c中,小张在这里介绍两种写法:

1、写死(简单,容易理解,灵活度低,改动麻烦)

c语言实现三子棋小游戏_第3张图片

 把棋盘它分成两个部分来分析,第一部分是 (" %c  | %c | %c "),第二部分是(“---|---|---”)三个%c对应的结果我们直接写出来即可。为了控制最后一行不打印分割行,写了个if()。

void printfboard(char board[ROW][COL],int row,int col)
{
	int i = 0;
	for (i = 0; i

2、复杂一点点(方便后续根据要求修改代码)

这段代码看起来比上面的代码复杂一些,实际上也是很容易理解的。我把棋盘的“ %c ”和‘|’看成一个部分;“---”和‘|’看成一个部分。

c语言实现三子棋小游戏_第4张图片

board[i][j],第i行,第j列

 ‘|’分隔符不是总打印的,和上面的逻辑是一样的,写了个if(row- 1)......来控制。

void printfboard(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 < col - 1)
				printf("|");
		}
		printf("\n");

		if (i < row - 1)

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


}

效果图(第一种写法的效果图是一样的):

c语言实现三子棋小游戏_第5张图片

假设我们想要把棋盘改成10*10,只需要更改 标识符常量行(ROW)和列(COL)即可:

#define ROW 10//表示行
#define COL 10//表示列

效果图:

c语言实现三子棋小游戏_第6张图片

 七、玩家1,玩家2轮流下棋

在game()函数中调用一个用来玩家1落子的函数play1move(board, ROW, COL);传入的3个参数分别是二维数组、行、列

调用一个用来玩家2落子的函数play2move(board, ROW, COL);传入的3个参数分别是二维数组、行、列

把这个和游戏相关的函数写在game.c中:

//玩家1下棋
void play1move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家1走:>");
	while (1)
	{
		printf("请输入棋子坐标:");
		scanf("%d %d", &x, &y);
		//判断棋子是否合法
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//落子
			//判断要下的坐标是否被占用
			//这里要注意,对下标进行访问是原坐标-1
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';

				break;
			}
			else
				printf("坐标已经被占用!");
		}
		else
			printf("坐标错误,请重新输入!");
	}
}

//玩家2下棋
void play2move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家2走:>");
	while (1)
	{
		printf("请输入棋子坐标:");
		scanf("%d %d", &x, &y);
		//判断棋子是否合法
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//落子
			//判断要下的坐标是否被占用
			//这里要注意,对下标进行访问是原坐标-1
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '#';

				break;
			}
			else
				printf("坐标已经被占用!");
		}
		else
			printf("坐标错误,请重新输入!");
	}
}

玩家1和2落子的逻辑是一样的,通过落子的坐标判断落子是否符合游戏规则,是否在棋盘内,落子坐标是否已经有棋子。这里要注意:控制台输入的x y坐标是数学上的坐标,但是判断坐标是否被占用的时候我们访问的是数组的下标,所以我们写成了(board[x - 1][y - 1]这样的形式!

效果图:

c语言实现三子棋小游戏_第7张图片

 八、判断游戏胜出、平局、继续

可能出现的四种游戏状态:规定每种状态下的返回值

玩家1胜:>'*'

出玩家2胜:>'#'

平局:>'A'

游戏继续:>'B'

在game()函数中调用一个用来判断胜负落子的函数iswin(board, ROW, COL);传入的3个参数分别是二维数组、行、列

游戏结果的判断分为几个方向:

1、三行有一样的棋子

因为胜出一方的返回值类型和棋子的字符是一样的,所以返回胜出行的任意一个字符即可!

2、三列有一样的棋子

因为胜出一方的返回值类型和棋子的字符是一样的,所以返回胜出列的任意一个字符即可!

3、对角线有一样的棋子

对角线的两种情况写死即可!

4、都不满足游戏继续 retun ‘B’;

5、返回1平局,返回0游戏继续,如果棋盘满了且没有连成一条线则平局

isswin()函数中调用isfull()函数来判断棋盘是否已满,满了返回1,没满返回0

int isfull(char ch[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for(i = 0; i
/判断游戏输赢
char iswin(char ch[ROW][COL], int row, int col)
{
	//当三个棋子连成一条线的时候,游戏胜利
	//判断三行有一样的棋子
	int i = 0;
	for (i = 0; i

九、、游戏测试 

1、玩家1胜利:

c语言实现三子棋小游戏_第8张图片

2、玩家2胜利:

c语言实现三子棋小游戏_第9张图片

3、平局:

c语言实现三子棋小游戏_第10张图片

十、总体代码:

1、game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

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;//棋盘满了
}

//初始化棋盘
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] = ' ';
		}
	}
}

打印棋盘
这种写法的灵活度低,当需求改变的时候我们要进行大量的修改
//void printfboard(char board[ROW][COL],int row,int col)
//{
//	int i = 0;
//	for (i = 0; i");
	while (1)
	{
		printf("请输入棋子坐标:");
		scanf("%d %d", &x, &y);
		//判断棋子是否合法
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//落子
			//判断要下的坐标是否被占用
			//这里要注意,对下标进行访问是原坐标-1
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';

				break;
			}
			else
				printf("坐标已经被占用!");
		}
		else
			printf("坐标错误,请重新输入!");
	}
}

//玩家2下棋
void play2move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家2走:>");
	while (1)
	{
		printf("请输入棋子坐标:");
		scanf("%d %d", &x, &y);
		//判断棋子是否合法
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//落子
			//判断要下的坐标是否被占用
			//这里要注意,对下标进行访问是原坐标-1
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '#';

				break;
			}
			else
				printf("坐标已经被占用!");
		}
		else
			printf("坐标错误,请重新输入!");
	}
}

//判断游戏输赢
char iswin(char ch[ROW][COL], int row, int col)
{
	//当三个棋子连成一条线的时候,游戏胜利
	//判断三行有一样的棋子
	int i = 0;
	for (i = 0; i < row; i++)
	{
		if (ch[i][0] == ch[i][1] && ch[i][1] == ch[i][2] && ch[i][1] != ' ')
		{
			return ch[i][1];
		}
	}
	//判断三列有一样的棋子
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (ch[0][j] == ch[1][j] && ch[1][j] == ch[2][j] && ch[1][j] != ' ')
		{
			return ch[1][j];
		}
	}

	//判断对角线
	if (ch[0][0] == ch[1][1] && ch[1][1] == ch[2][2] && ch[1][1] != ' ')
	{
		return ch[1][1];
	}
	if (ch[0][2] == ch[1][1] && ch[1][1] == ch[2][0] && ch[1][1] != ' ')
	{
		return ch[1][1];
	}

	//判断是否平局,棋盘是否已经满了
	//返回1平局,返回0继续游戏
	int ret = isfull(ch, row, col);
	if (ret == 1)
	{

		return 'A';
	}
	//继续
	return 'B';
}

2、game.h

#pragma once
//头文件
#include 
//符号的定义
#define ROW 3//表示行
#define COL 3//表示列

//函数的声明
//初始化棋盘的函数
void initboard(char board[ROW][COL], int row, int col);

//打印棋盘的函数
void printfboard(char board[ROW][COL], int row, int col);
//玩家1落子
void play1move(char board[ROW][COL], int row, int col);
//玩家2落子
void play2move(char board[ROW][COL], int row, int col);
//判断输赢
char  iswin(char board[ROW][COL], int row, int col);

3、 text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
 void menu()
{
	printf("----------- Tic-Tac-Toe -----------\n");
	printf("*********** 1.开始游戏 ************\n");
	printf("*********** 0.退出游戏 ************\n");
	printf("-----------------------------------\n");
	
}
 void game()
 {
	 //字符数组存储数据
	 char board[ROW][COL];
	 //初始化棋盘
	 initboard(board, ROW, COL);
	 //打印棋盘
	 printfboard(board,ROW,COL);
	 char ret = 0;
	 while (1)
	 {
		 //玩家1走
		 play1move(board, ROW, COL);
		 printfboard(board, ROW, COL);
		 ret = iswin(board, ROW, COL);
		 if (ret != 'B')
			 break;
		 //玩家2走
		 play2move(board, ROW, COL);
		 printfboard(board, ROW, COL);
		 ret = iswin(board, ROW, COL);
		 if (ret != 'B')
			 break;
	 }
	 if (ret == '*')
	 {
		 printf("玩家1胜利!\n");
	 }
	 else if (ret == '#')
	 {
		 printf("玩家2胜利!\n");
	 }
	 else
	 {
		 printf("平局!\n");
	 }
	 printfboard(board, ROW, COL);
 }
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入选项:>\n");
		scanf("%d", &input);
		printf("\n");
		switch (input)
		{
		case 1:
			game();
			/*printf("游戏开始!\n");*/
			break;
		case 0:
			printf("退出游戏!\n");
			break;

		default:
			printf("选项错误,请重新输入:");
		}
		printf("\n");
	} while (input);
	
	
	return 0;
}

你可能感兴趣的:(学习,c语言)