一,游戏的基本框架

游戏中有人机,双人两种模式。五子棋作为一个平面游戏,很明显用二维数组来写最合适不过。为了让代码看起来更有条理,我们用三个.c文件,分别是:text.c 用来测试我们的游戏;game.c 游戏功能的实现;is_win.c 判断输赢的版块。另外,还有一个game.h 文件来放我们的函数声明和头文件。


二 、主函数的设计

主函数的主要逻辑我们用switch,case语句来实现,为了能够在选择错误后重新选择,我们在switch 语句外层又嵌套了do while语句来实现循环,且循环终止条件就是游戏的退出的条件,代码如下:

int main()
{
	srand((unsigned int)time(NULL));
	int input;
	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game1();
			break;
		case 2:
			game2();
			break;
		case 0:
			printf("退出\n");
			break;
		default:
			printf("请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}

其中,game1()表示人机模式,game2()表示双人模式。

三、重要功能设计

3.1 游戏界面的设计

代码如下:

void menu()
{
	printf("*************************\n");
	printf("*****1.人机   2.双人*****\n");
	printf("******** 0.退出  ********\n");
	printf("*************************\n");

}

3.2棋盘的初始化

上面我们提到“五子棋作为一个平面游戏,很明显用二维数组来写最合适不过”因此,我们定义一个行为ROW,列为COL的二维数组,并将其初始化为’ ',代码如下:

void Init_board(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

代码运行结果如图:
在这里插入图片描述

3.3棋盘的设计

如图,这是我们想要的棋盘设计结果
在这里插入图片描述
我们先打印“ %c ”,再打印“ | ”,利用for循环完成一行的打印,这里我们要注意的是:当打印完每行最后一个“ %c”时,是不需要再次打印“ | ”的,因此在这里我们加一个if语句进行判断,当j<col-1时才进行“ | ”的打印。
代码如下:

for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}

当每打印完上述的一行后,我们进行换行后,打印“—|”,再次利用for循环进行一行的打印,在这里也要注意当进行一行的最后一次打印时我们只需要打印“—”,因此在这里我们需要加一个if,else 的判断语句,代码如下:

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

最后我们再用一个for循环进行多行的打印,完整代码如下:

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

3.4 玩家下棋

玩家输入坐标,在这里要注意的是玩家输入的坐标减一才是我们二维数组的下标。

scanf("%d%d", &x, &y);
		i = x - 1;
		j = y - 1;

当输入坐标后,我们要进行坐标的合理性判断:1.所输入坐标是否超出棋盘范围;2.所输入坐标是否已被占用。如果所输入坐标合理,则将坐标位置赋予一定的字符(本游戏中,在人机对战中,玩家所下为**‘,在双人对战中,玩家一所下为,玩家二为‘#’**);若坐标不合理,则提示后重新输入。

int player_board(char board[ROW][COL], int row, int col)
{
	printf("玩家下:\n");
	int i = 0;
	int j = 0;
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d%d", &x, &y);
		i = x - 1;
		j = y - 1;
		if (x >= 1 && y >= 1 && x <= row && y <= col)
		{
			if (board[i][j] != ' ')
			{
				printf("此坐标已经被占用,请重新下:\n");
			}
			else
			{
				board[i][j] = '*';
				int ret = is_win(board, ROW, COL, &i, &j, '*');
				return ret;
			}
		}
		else
		{
			printf("非法坐标,请重新下:\n");
		}
	}
}

运行结果:
在这里插入图片描述

3.5 电脑下棋

电脑下棋我们采用的是通过随机数函数生成合理坐标,然后进行下棋(电脑所下为**‘#’**)。这里要注意的就是随机函数srand(),必须与srand()函数,时间戳搭配使用,且srand()函数只能调用一次,我们在主函数中进行调用。

int main()
{
	srand((unsigned int)time(NULL))//srand()函数的调用;
	//由于srand函数的参数为无符号数,因此要将时间戳(time函数)的返回值类型强转化为无符号数。
int computer_board(char board[ROW][COL], int row, int col)
{
	printf("电脑下:\n");
	while (1)
	{
		int ret1 = rand() % row;
		int ret2 = rand() % col;
		if (board[ret1][ret2] == ' ')
		{
			board[ret1][ret2] = '#';
			int ret = is_win(board, ROW, COL, &ret1, &ret2, '#');
			return ret;
		}
	}
}

运行结果:
在这里插入图片描述

3.6 胜负判断

3.6.1 行的判断

我们通过所下的坐标来找到当前行的最左端,然后对这一行进行遍历,如果发现了有五个连续且一样的字符,则获胜。代码如下:

int Col_win(char board[ROW][COL], int row, int col, int* ret1, char ret)
{
	int count = 0;
	for (int i = 0; i < col; i++)
	{
		if (board[*ret1][i] == ret)
		{
			count++;
		}
		if (count == renju)
		{
			break;
		}
		if (i + 1 <= col && board[*ret1][i + 1] != ret)
		{
			count = 0;
		}
	}
	if (count == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}
	return 3;
}

3.6.2 列的判断

与上述行的判断一样,我们通过所下的坐标来找到当前列的最上端,然后对这一行进行遍历,如果发现了有五个连续且一样的字符,则获胜。代码如下:

int Row_win(char board[ROW][COL], int row, int col, int* ret2, char ret)
{
	int count = 0;
	for (int i = 0; i < row; i++)
	{
		if (board[i][*ret2] == ret)
		{
			count++;
		}
		if (count == renju)
		{
			break;
		}
		if (i + 1 <= row && board[i + 1][*ret2] != ret)
		{
			count = 0;
		}
	}
	if (count == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}
	return 3;
}

3.6.3 对角的判断

通过所下的坐标来找到当前对角的端点,对对角进行遍历,若有五个连续且相同的字符,则获胜。
代码如下;

int Dia1_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	//下半角
	int count1 = 0;
	for (int i = 0; i < row && i < col; i++)
	{
		if (board[*ret1 - (*ret2 - i)][i] == ret)
		{
			count1++;
		}
		if (count1 == renju)
		{
			break;
		}
		if (i + 1 < col && board[*ret1 - (*ret2 - i - 1)][i + 1] != ret)
		{
			count1 = 0;
		}
	}
	if (count1 == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}

	//上半角

	int count2 = 0;
	for (int i = col - 1; i >= 0; i--)
	{
		if (board[*ret1 + (i - *ret2)][i] == ret)
		{
			count2++;
		}
		if (count2 == renju)
		{
			break;
		}
		if (i - 1 > 0 && board[*ret1 + (i - *ret2)][i - 1] != ret)
		{
			count2 = 0;
		}
	}
	if (count2 == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}
	return 3;

}
int Dia2_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	//上半角
	int count1 = 0;
	for (int i = 0; i < row && i < col; i++)
	{
		if (board[*ret1 + *ret2 - i][i] == ret)
		{
			count1++;
		}
		if (count1 == renju)
		{
			break;
		}
		if (i + 1 < col && board[*ret1 + *ret2 - i - 1][i + 1] != ret)
		{
			count1 = 0;
		}
	}
	if (count1 == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}

	//下半角

	int count2 = 0;
	for (int i = col - 1; i >= 0; i--)
	{
		if (*ret1 - (i - *ret2) >= 0 && board[*ret1 - (i - *ret2)][i] == ret)
		{
			count2++;
		}
		if (count2 == renju)
		{
			break;
		}
		if (i - 1 > 0 && board[*ret1 - (i - *ret2) + 1][i - 1] != ret)
		{
			count2 = 0;
		}
	}
	if (count2 == renju)
	{
		if (ret == '#')
		{
			return 1;
		}
		if (ret == '*')
		{
			return 2;
		}
	}
	return 3;

}

3.6.4 判断平局

我们将整个二维数组遍历一遍,在没有获胜的前提下,若没有发现**‘ ’,则证明棋盘已下满——平局;若发现了‘ ’**,则继续游戏。代码如下:

int is_full(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 4;
}

四.game.h文件

此文件里主要是一些函数声明,头文件和宏定义。

#define ROW 7//定义行
#define COL 7//定义列
#define renju 5//定义几子琪
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void Init_board(char board[ROW][COL], int row, int col);
void print_board(char board[ROW][COL], int row, int col);
int player_board(char board[ROW][COL], int row, int col);
int player_board1(char board[ROW][COL], int row, int col);
int player_board2(char board[ROW][COL], int row, int col);
int computer_board(char board[ROW][COL], int row, int col);
int is_full(char board[ROW][COL], int row, int col);
int is_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret);
int is_win2(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret);

五. 完整代码

//text.c

#include"game.h"
void game1()
{
	int flag = 0;
	char board[ROW][COL] = { 0 };
	Init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	while (1)
	{
		int ret1 = player_board(board, ROW, COL);
		if (ret1 == 1 || ret1 == 0)
		{
			print_board(board, ROW, COL);
			break;
		}
		print_board(board, ROW, COL);
		int ret2 = computer_board(board, ROW, COL);
		if (ret2 == 1 || ret1 == 0)
		{
			print_board(board, ROW, COL);
			break;
		}
		print_board(board, ROW, COL);
	}
}
//双人
void game2()
{
	int flag = 0;
	char board[ROW][COL] = { 0 };
	Init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	while (1)
	{
		int ret1 = player_board1(board, ROW, COL);
		if (ret1 == 1 || ret1 == 0)
		{
			print_board(board, ROW, COL);
			break;
		}
		print_board(board, ROW, COL);
		int ret2 = player_board2(board, ROW, COL);
		if (ret2 == 1 || ret1 == 0)
		{
			print_board(board, ROW, COL);
			break;
		}
		print_board(board, ROW, COL);
	}
}
void menu()
{
	printf("*************************\n");
	printf("*****1.人机   2.双人*****\n");
	printf("******** 0.退出  ********\n");
	printf("*************************\n");

}
int main()
{
	srand((unsigned int)time(NULL));
	int input;
	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game1();
			break;
		case 2:
			game2();
			break;
		case 0:
			printf("退出\n");
			break;
		default:
			printf("请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}
//game.h

#include"game.h"
void Init_board(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
void print_board(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		for (int i = 0; i < col; i++)
		{
			if (i < col - 1)
			{
				printf("---|");
			}
			else
			{
				printf("---");
			}
		}
		printf("\n");
	}
}
int player_board(char board[ROW][COL], int row, int col)
{
	printf("玩家下:\n");
	int i = 0;
	int j = 0;
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d%d", &x, &y);
		i = x - 1;
		j = y - 1;
		if (x >= 1 && y >= 1 && x <= row && y <= col)
		{
			if (board[i][j] != ' ')
			{
				printf("此坐标已经被占用,请重新下:\n");
			}
			else
			{
				board[i][j] = '*';
				int ret = is_win(board, ROW, COL, &i, &j, '*');
				return ret;
				//break;
			}
		}
		else
		{
			printf("非法坐标,请重新下:\n");
		}
	}
}

int computer_board(char board[ROW][COL], int row, int col)
{
	printf("电脑下:\n");
	while (1)
	{
		int ret1 = rand() % row;
		int ret2 = rand() % col;
		if (board[ret1][ret2] == ' ')
		{
			board[ret1][ret2] = '#';
			int ret = is_win(board, ROW, COL, &ret1, &ret2, '#');
			return ret;
			//break;
		}
	}
}
//双人
int player_board1(char board[ROW][COL], int row, int col)
{
	printf("玩家下A:\n");
	int i = 0;
	int j = 0;
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d%d", &x, &y);
		i = x - 1;
		j = y - 1;
		if (x >= 1 && y >= 1 && x <= row && y <= col)
		{
			if (board[i][j] != ' ')
			{
				printf("此坐标已经被占用,请重新下:\n");
			}
			else
			{
				board[i][j] = '*';
				int ret = is_win2(board, ROW, COL, &i, &j, '*');
				return ret;
				//break;
			}
		}
		else
		{
			printf("非法坐标,请重新下:\n");
		}
	}
}
int player_board2(char board[ROW][COL], int row, int col)
{
	printf("玩家下B:\n");
	int i = 0;
	int j = 0;
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d%d", &x, &y);
		i = x - 1;
		j = y - 1;
		if (x >= 1 && y >= 1 && x <= row && y <= col)
		{
			if (board[i][j] != ' ')
			{
				printf("此坐标已经被占用,请重新下:\n");
			}
			else
			{
				board[i][j] = '#';
				int ret = is_win2(board, ROW, COL, &i, &j, '#');
				return ret;
				//break;
			}
		}
		else
		{
			printf("非法坐标,请重新下:\n");
		}
	}
}


//is_win.c

#include"game.h" 
//判断行
int Col_win(char board[ROW][COL], int row, int col, int* ret1, char ret)
{
	int count = 0;
	for (int i = 0; i < col; i++)
	{
		if (board[*ret1][i] == ret)
		{
			count++;
		}
		if (count == renju)
		{
			break;
		}
		if (i + 1 <= col && board[*ret1][i + 1] != ret)
		{
			count = 0;
		}
	}
	if (count == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}
	return 3;
}
//判断列
int Row_win(char board[ROW][COL], int row, int col, int* ret2, char ret)
{
	int count = 0;
	for (int i = 0; i < row; i++)
	{
		if (board[i][*ret2] == ret)
		{
			count++;
		}
		if (count == renju)
		{
			break;
		}
		if (i + 1 <= row && board[i + 1][*ret2] != ret)
		{
			count = 0;
		}
	}
	if (count == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}
	return 3;
}
//左
int Dia1_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	//下半角
	int count1 = 0;
	for (int i = 0; i < row && i < col; i++)
	{
		if (board[*ret1 - (*ret2 - i)][i] == ret)
		{
			count1++;
		}
		if (count1 == renju)
		{
			break;
		}
		if (i + 1 < col && board[*ret1 - (*ret2 - i - 1)][i + 1] != ret)
		{
			count1 = 0;
		}
	}
	if (count1 == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}

	//上半角

	int count2 = 0;
	for (int i = col - 1; i >= 0; i--)
	{
		if (board[*ret1 + (i - *ret2)][i] == ret)
		{
			count2++;
		}
		if (count2 == renju)
		{
			break;
		}
		if (i - 1 > 0 && board[*ret1 + (i - *ret2)][i - 1] != ret)
		{
			count2 = 0;
		}
	}
	if (count2 == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}
	return 3;

}
int Dia2_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	//上半角
	int count1 = 0;
	for (int i = 0; i < row && i < col; i++)
	{
		if (board[*ret1 + *ret2 - i][i] == ret)
		{
			count1++;
		}
		if (count1 == renju)
		{
			break;
		}
		if (i + 1 < col && board[*ret1 + *ret2 - i - 1][i + 1] != ret)
		{
			count1 = 0;
		}
	}
	if (count1 == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}

	//下半角

	int count2 = 0;
	for (int i = col - 1; i >= 0; i--)
	{
		if (*ret1 - (i - *ret2) >= 0 && board[*ret1 - (i - *ret2)][i] == ret)
		{
			count2++;
		}
		if (count2 == renju)
		{
			break;
		}
		if (i - 1 > 0 && board[*ret1 - (i - *ret2) + 1][i - 1] != ret)
		{
			count2 = 0;
		}
	}
	if (count2 == renju)
	{
		if (ret == '#')
		{
			//printf("电脑赢了");
			return 1;
		}
		if (ret == '*')
		{
			//printf("你赢了");
			return 2;
		}
	}
	return 3;

}
int is_full(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 4;
}
int is_win(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	int a = Col_win(board, row, col, ret1, ret);
	int b = Row_win(board, row, col, ret2, ret);
	int c = Dia1_win(board, row, col, ret1, ret2, ret);
	int d = Dia2_win(board, row, col, ret1, ret2, ret);
	int e = is_full(board, row, col);
	if (e == 0)
	{
		if (a == 1 || b == 1 || c == 1 || d == 1)
		{
			printf("电脑赢了\n");
			return 1;
		}
		else if (a == 2 || b == 2 || c == 2 || d == 2)
		{
			printf("你赢了\n");
			return 1;
		}
		else
		{
			return 2;
		}
	}
	else
	{
		printf("平局\n");
		return 0;
	}
}
//双人
int is_win2(char board[ROW][COL], int row, int col, int* ret1, int* ret2, char ret)
{
	int a = Col_win(board, row, col, ret1, ret);
	int b = Row_win(board, row, col, ret2, ret);
	int c = Dia1_win(board, row, col, ret1, ret2, ret);
	int d = Dia2_win(board, row, col, ret1, ret2, ret);
	int e = is_full(board, row, col);
	if (e == 0)
	{
		if (a == 1 || b == 1 || c == 1 || d == 1)
		{
			printf("B赢了\n");
			return 1;
		}
		else if (a == 2 || b == 2 || c == 2 || d == 2)
		{
			printf("A赢了\n");
			return 1;
		}
		else
		{
			return 2;
		}
	}
	else
	{
		printf("平局\n");
		return 0;
	}
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐