C语言小游戏之——三子棋

首先我们给出代码,结合代码我们进行解释:

首先,我们可以将游戏的进入及退出写入一个test函数,然后在主函数里只需写test();就可以访问了,主函数内不需要写太多的东西。

void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");

		}
	} while (input);
}

这是test函数内部,通过输入一个input变量来控制游戏的进入和退出,menu则是一个简易的的游戏菜单,提示输入的数代表的功能。输入1来进入game()函数,输入0来退出游戏,输入其他数时default提示输入错误,用do while()循环结构,input非零循环继续,为零退出游戏。而system("cls")是清空屏幕,可以先不管,写不写无所谓,主要是改善游戏体验的。

下面是menu函数:

void menu()
{
	printf("************************************************************\n");
	printf("**1.Start                                           0.Exit**\n");
	printf("************************************************************\n");
}

简易的游戏菜单。

当输入1时,进入game()函数,在game()函数内实现游戏的逻辑。

下面是game()函数:

void game()
{
	char result = 0;
	//储存棋盘信息
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		system("cls");
		DisplayBoard(board, ROW, COL);
		//判断输赢
		result = IsWin(board, ROW, COL);
		if (result != 'C')
		{
			break;
		}
		//电脑下棋
		Sleep(500);
		ComputerMove(board, ROW, COL);
		system("cls");
		DisplayBoard(board, ROW, COL);
		result = IsWin(board, ROW, COL);
		if (result != 'C')
		{
			break;
		}
	}
	if (result == '*')
	{
		system("cls");
		DisplayBoard(board, ROW, COL);
		printf("玩家获胜\n");
	}
	if (result == '#')
	{
		system("cls");
		DisplayBoard(board, ROW, COL);
		printf("电脑获胜\n");
	}
	if (result == 'E')
	{
		system("cls");
		DisplayBoard(board, ROW, COL);
		printf("平局\n");
		
	}
	
}

同样,里面的system("cls");可忽略。然后,我们创建一个game.h文件来进行game()函数内部出现的函数的定义。再写一个game.c文件用来实现game.h内的函数。当用到自己定义的头文件时,写为#include "game.h"然后在game.c和test.c的首部写上#include "game.h",不妨把库函数也包含在game.h内部,这样只需引用一个game.h就行了。

下面是game.h内部:

#pragma once
#include 
#include 
#include 
#include 
#define ROW 3
#define COL 3
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoardw(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);
char IsWin(char board[ROW][COL], int row, int col);
int IsFull(char board[ROW][COL], int row, int col);

结合前面的game函数内部,每个函数所需要的参数是一个二维数组,所以我们向函数里传的是一个数组,然后传入数组的行和列,分别用数组和两个整形接收。为了能规定棋盘的大小以及易于改变,所以我们在game.h内部用了宏定义,将二维数组的行(ROW)和列(COL)进行了规定

游戏逻辑在game函数内,下面我们对具体函数的实现进行说明:

首先我们需要一个二维数组来储存棋盘信息而下棋时,我们用”*“来代表玩家落子,用"#"来代表电脑落子,所以我们创建的二维数组是char类型的用来存放字符。

第二初始化棋盘,即给数组的每个元素初始化为空格,下面是代码:

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 DisplayBoard(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++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
		
	}
	
}

先打印一行的数据,每个元素为空格、数组中元素内容、空格,然后再打印一个竖杠,而第三列的时候我们不需要最后的竖杠,所以给打印竖杠的前面加上限制条件,当 j < col - 1时才打印竖杠,然后一行就打印完了,每行打印完打一个换行,确定为三行三列,之后打印分割行,即---,而当最后一行时,不需要打印分割行,所以也要给打印分割行时加上限制条件,即i < row - 1,然后打印---后面的那个竖杠,限制条件和前面打印竖杠时限制条件一样。打印完每行后记得换行。

玩家下棋:

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");
		}
	}
}

即玩家落子,选中坐标,若所选的地方在数组范围内,则继续判断,否则输出非法输入,若在棋盘范围内,则继续判断是否为空格,即是否已经落子,没有的话就将空格改为*,否则输出被占用信息。

注意输入的是位置,而数组的下标是从零开始,所以在以下标形式访问数组元素时输入的x和y要分别减一。

将此过程放入循环内,一旦落子成功便跳出循环。

接下来我们说电脑下棋,由于只是简单的实现,所以我们给电脑的坐标设值是随机数,即x = rand(),但是要在数组范围内,所以分别模上row和col,确保只产生0到2的数所以x = rand() % row

y = rand() % col。而要使用随机数,就要使用srand((unsigned int)time(NULL));设置随机起点,只需设一次,所以放在main函数内部。

int main()
{
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

而对电脑的落子,只需判断所下的地方是否被占用即可,因为不可能超出范围。

放到循环里直到落子成功后break跳出循环。

最主要的是判断部分:

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 'C';
	}
	else
	{
		return 'E';
	}

}

判断三行相等、三列相等、对角线相等。

我们规定若相等而且不能等于空格,我们就返回相等的三个里面的任意一个,如玩家赢为返回*,电脑赢为返回#。还有就是棋盘下满为平局,我们返回E,二者都没赢而且棋盘没满就返回C,而在每次玩家落子之后、电脑落子之后都要判断。

玩家下棋和电脑下棋是一个循环往复,直到游戏结束的过程,所以是循环结构,当返回的不是C即说明游戏结束了,所以跳出来判断,若返回为*玩家赢,返回为#电脑赢,返回为E平局。

而判断棋盘是否满了,就要再写一个函数:

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 1;
			}
		}
	}
	return -1;
}

遍历数组,发现有空格就返回1,没有即返回-1,有空格说明棋盘没满。

若返回1,在判断函数里就返回字符C,若返回-1,在判断函数里就返回E,注意判断满没满是要在判断了赢没赢之后的。

以上就是对三子棋的C语言实现的过程解释,水平有限,欢迎指正。

你可能感兴趣的:(c语言,开发语言,后端)