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

3 篇文章 0 订阅

游戏规则

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

创建棋盘

我们要设计这个游戏,首先就出现几个问题。
如何设计棋盘呢? 创建一个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;
  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值