C语言实现:数组:三子棋游戏

【摘要】 游戏规则
有如下图的一个棋盘,一方下白子,一方下黑子,直到出现第一个三点一线,游戏结束!
创建棋盘
我们要设计这个游戏,首先就出现几个问题。 如何设计棋盘呢? 创建一个3*3的二维数组,每个元素是一个 char类型。 用‘x’表示黑子(玩家1),用‘o’表示白子(玩家2),用‘ ’(空格)表示空白,这样,棋盘就设计好了。
游戏流程
1、创建棋盘,并且初始化~…

游戏规则

有如下图的一个棋盘,一方下白子,一方下黑子,直到出现第一个三点一线,游戏结束!
在这里插入图片描述

创建棋盘

我们要设计这个游戏,首先就出现几个问题。
如何设计棋盘呢? 创建一个3*3的二维数组,每个元素是一个 char类型。
用‘x’表示黑子(玩家1),用‘o’表示白子(玩家2),用‘ ’(空格)表示空白,这样,棋盘就设计好了。

游戏流程

1、创建棋盘,并且初始化~ 把所有的位置都设为空格~

 做两个循环就可以啦,一个控制行,一个控制列

  
 
void init(char chess[MAX_ROW][MAX_COL]) 
{
	for (int row = 0; row < MAX_ROW; row++) 
	{
		for (int col = 0; col < MAX_COL; col++) { chess[row][col] = ' ';
		}
	} //注意这里MAX_ROW 和MAX_COL的值,虽然我们知道是三,但还是要进行宏定义,这样可以避免重复的3的意义,提高代码的可读性
}

  
 

2、打印棋盘~

 我们需要做一个打印函数; 一是要把chess[row][col]打印出来; 二是要把棋盘作美化;

  
 
void print(char chess[MAX_ROW][MAX_COL])
 {
	printf("+---+---+---+\n");
	for (int row = 0; row < MAX_ROW; row++) 
	{
		printf("|");
		for (int col = 0; col < MAX_COL; col++) { printf(" %c |", chess[row][col]);
		}
		printf("\n+---+---+---+\n");
	}
}

  
 

我们来看一下效果:
在这里插入图片描述
是不是很可观呢?

3、玩家进行落子~ 我们创建的是二维数组,就让玩家输入一组坐标(row,col)进行落子~

 玩家进行落子,是不是玩家一次,电脑一次,玩家一次……这是一个循环呀!
 但这里我们还需要注意的问题是:玩家会不会胡乱输入呀?有两种情况: 1.输入的位置超出chess数组范围,就是下到棋盘外面去了; 2.输入的位置之前以及有子了; 这就需要我们进行合法性判定了;
 那怎么落子啊?  输入对应位置坐标,将该位置的棋盘初始化成‘*’就好了

  
 
void playerMove(char chessBoard[MAX_ROW][MAX_COL])
 {
	printf("玩家落子....\n");
	while (1) 
	{
		printf("请输入坐标(row col): ");
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		// 进行合法性判定
		//是否越界,合法继续,不合法重新输入
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) { printf("您输入的坐标非法! 请重新输入!\n"); continue;
		}
		//是否有子
		if (chessBoard[row][col] != ' ') { printf("您输入的位置已经有子了, 请重新输入!\n"); continue;
		}
		// 进行落子~~
		chessBoard[row][col] = 'x';
		break;
	}
}

  
 

4、判定获胜~

 判定胜负有三种情况,玩家胜,电脑胜,和棋! 1.胜负:遍历所有行,所有列,还有对角线,有对应的三个数不为空格且相等就说明游戏结束了,我们返回这条线上的任意一个文章,如果是‘x’,就说明玩家胜,如果是‘o’,就是电脑胜了 2.和棋:判定标准就是,只要棋盘满了就和棋了。遍历棋盘所有位置,不是空格就满了。 这里我们分别设置一个函数来判断!来看操作:

  
 
// 返回 1 表示满了, 返回 0 表示没满
int isFull(char chessBoard[MAX_ROW][MAX_COL]) 
{
	// 遍历棋盘, 看看有没有空格. 有空格就是没满~~
	for (int row = 0; row < MAX_ROW; row++) 
	{
		for (int col = 0; col < MAX_COL; col++) { if (chessBoard[row][col] == ' ') { return 0; }
		}
	}
	return 1;
}

// 此处约定,
// 如果返回 x, 表示 玩家获胜
// 如果返回 o, 表示 电脑获胜
// 如果返回 ' ', 表示胜负未分, 还要继续下棋
// 如果返回 q, 表示和棋
char isGameOver(char chessBoard[MAX_ROW][MAX_COL]) 
{
	// 扫描所有的行, 所有的列, 以及两个对角线~~
	for (int row = 0; row < MAX_ROW; row++) 
	{
		if (chessBoard[row][0] != ' ' && chessBoard[row][0] == chessBoard[row][1] && chessBoard[row][0] == chessBoard[row][2]) { return chessBoard[row][0];
		}
	}
	for (int col = 0; col < MAX_COL; col++) 
	{
		if (chessBoard[0][col] != ' ' && chessBoard[0][col] == chessBoard[1][col] && chessBoard[0][col] == chessBoard[2][col]) { return chessBoard[0][col];
		}
	}
	if (chessBoard[0][0] != ' '
		&& chessBoard[0][0] == chessBoard[1][1]
		&& chessBoard[0][0] == chessBoard[2][2]) {
		return chessBoard[0][0];
	}
	if (chessBoard[0][2] != ' '
		&& chessBoard[0][2] == chessBoard[1][1]
		&& chessBoard[0][2] == chessBoard[2][0]) {
		return chessBoard[0][2];
	}
	// 判定是否和棋
	if (isFull(chessBoard)) 
	{
		return 'q';
	}
	// 胜负未分
	return ' ';
}

  
 

5、电脑进行落子~(随机落子)

 电脑怎么进行落子呀?把某个位置(空位置)初始化成‘o’就好了 这里我们需要注意两个关键词: 随机 空位置 看到空位置,我们就知道进行合法性判断啦,不能落在以及有子的位置。那我们为什么不判断落子的位置是否越界呢? 这就需要注意到随机啦,上次的猜数字游戏中我们谈到,使用rand()函数可以自定义随机数产生的范围,还记得用法吗? rand()%rand_max求0~rand_max的随机值;   rand()% (Y-X+1)+X;X~Y的随机值 注意这样产生的随机数是固定的,如果需要每次运行都产生不同的随机数,我们就需要借助时间戳了。引入随机数种子srand((unsigned int )time(NULL));即可

  
 
void computerMove(char chessBoard[MAX_ROW][MAX_COL]) 
{
	while (1) {
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (chessBoard[row][col] != ' ')
		{ // 这个位置已经有子了 continue;
		}
		chessBoard[row][col] = 'o';
		break;
	}
}

  
 

6、判定获胜~

代码同上,逻辑上这一步存在的意义是:玩家落子完,判断胜负;电脑落子完,判断胜负;

  
 

完整实现

#define MAX_ROW 3
#define MAX_COL 3
void init(char chess[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) { chess[row][col] = ' ';
		}
	}
}

void print(char chess[MAX_ROW][MAX_COL]) {
	printf("+---+---+---+\n");
	for (int row = 0; row < MAX_ROW; row++) {
		printf("|");
		for (int col = 0; col < MAX_COL; col++) { printf(" %c |", chess[row][col]);
		}
		printf("\n+---+---+---+\n");
	}
}

void playerMove(char chessBoard[MAX_ROW][MAX_COL]) {
	printf("玩家落子....\n");
	while (1) {
		printf("请输入坐标(row col): ");
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		// 进行合法性校验, 判定用户输入的内容是否是合法的
		// 如果不合法, 就让用户重新输入
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) { // 就是不合法, 于是要让用户重新输入 printf("您输入的坐标非法! 请重新输入!\n"); continue;
		}
		// 假设用户输入了1, 1, 但是 1 1 位置已经有子了~~ 
		if (chessBoard[row][col] != ' ') { // 该位置已经有子了 printf("您输入的位置已经有子了, 请重新输入!\n"); continue;
		}
		// 进行落子~~
		chessBoard[row][col] = 'x';
		break;
	}
}

void computerMove(char chessBoard[MAX_ROW][MAX_COL]) {
	while (1) {
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (chessBoard[row][col] != ' ') { // 这个位置已经有子了 continue;
		}
		chessBoard[row][col] = 'o';
		break;
	}
}

// 返回 1 表示满了, 返回 0 表示没满
int isFull(char chessBoard[MAX_ROW][MAX_COL]) {
	// 遍历棋盘, 看看有没有空格. 有空格就是没满~~
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) { if (chessBoard[row][col] == ' ') { return 0; }
		}
	}
	return 1;
}

// 此处约定,
// 如果返回 x, 表示 玩家获胜
// 如果返回 o, 表示 电脑获胜
// 如果返回 ' ', 表示胜负未分, 还要继续下棋
// 如果返回 q, 表示和棋
char isGameOver(char chessBoard[MAX_ROW][MAX_COL]) {
	// 扫描所有的行, 所有的列, 以及两个对角线~~
	for (int row = 0; row < MAX_ROW; row++) {
		if (chessBoard[row][0] != ' ' && chessBoard[row][0] == chessBoard[row][1] && chessBoard[row][0] == chessBoard[row][2]) { return chessBoard[row][0];
		}
	}
	for (int col = 0; col < MAX_COL; col++) {
		if (chessBoard[0][col] != ' ' && chessBoard[0][col] == chessBoard[1][col] && chessBoard[0][col] == chessBoard[2][col]) { return chessBoard[0][col];
		}
	}
	if (chessBoard[0][0] != ' '
		&& chessBoard[0][0] == chessBoard[1][1]
		&& chessBoard[0][0] == chessBoard[2][2]) {
		return chessBoard[0][0];
	}
	if (chessBoard[0][2] != ' '
		&& chessBoard[0][2] == chessBoard[1][1]
		&& chessBoard[0][2] == chessBoard[2][0]) {
		return chessBoard[0][2];
	}
	// 判定是否和棋
	if (isFull(chessBoard)) {
		return 'q';
	}
	// 胜负未分
	return ' ';
}

int main()
{
	// 不建议使用全局变量
	// 搜索树
	char chessBoard[MAX_ROW][MAX_COL];
	// 1. 对棋盘进行初始化
	init(chessBoard);
	char winner = ' ';
	while (1) {
		// 2. 打印棋盘
		print(chessBoard);
		// 3. 玩家落子
		playerMove(chessBoard);
		// 4. 判定胜负
		winner = isGameOver(chessBoard);
		if (winner != ' ') { // 游戏结束 break;
		}
		// 5. 电脑落子
		computerMove(chessBoard);
		// 6. 判定胜负
		winner = isGameOver(chessBoard);
		if (winner != ' ') { // 游戏结束 break;
		}
	}
	if (winner == 'x') {
		printf("恭喜你赢了!\n");
	}
	else if (winner == 'o') {
		printf("你咋连人工智障都下不过!\n");
	}
	else {
		printf("你和人工智障五五开!\n");
	} system("pause");
	return 0;

  
 

文章来源: blog.csdn.net,作者:Diligent_wu,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Diligent_wu/article/details/116139337

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享