带你快速实现【C语言】之三子棋(简易版)

一.下棋逻辑

我们先来看看一个完整版三子棋例子 

1380fa77ba804a168b8e01be34dc1788.png

图里的要素有:菜单,棋盘,玩家走,电脑走。我们一步步分析

1.菜单

我们每次三子棋运行,不管你选择什么是不是都会呈现出一个菜单呢?所以我们优先用 do while结构,这样,不论玩家选什么,菜单都会打印一次。

接下来是菜单的内容,选择1我们进行游戏,选择0退出游戏,自然的我们会想到分支语句。这里我们选择switch。

最后,我们要来封装menu函数。具体实现用printf就好。但也要注意格式美观。

 


int main()
{
	int imput = 0;
	do {
		menu();
		printf("请选择->");
		scanf("%d", &imput);
		switch (imput)
		{
		case 1:
			printf("\n开始游戏!\n\n");
			game();
			break;
		case 0:
			printf("再见\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (imput);

}

 

void menu()
{
	printf("\n");
	printf("|--欢迎来到三子棋--|\n");
	printf("|******************|\n");
	printf("|******1.play******|\n");
	printf("|******0.exit******|\n");
	printf("|------------------|\n");
}

2.棋盘

可以看到我们的棋盘是由3*3的横竖线组成的,这是不是和二维数组很像呢?所以我们用二维数组来实现棋盘。

eff027cd89ff4c03836caf529e019575.png

	char board[ROW][COL];

这里提一句二维数组不定义成board[3][3] ,是为了方便修改,如果想实现五子棋或者其他的,只需要在define处修改就行,提升了代码通用性。

fc0d962dbd7c4f11b20e2cb1c009e134.png

 

定义完数组后,一定要记得初始化!这里用两个for遍历二维数组把数组初始化成空格。

void init(char board[ROW][COL], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		for (j = 0; j < c; j++)
		{
			board[i][j] = ' ';
		}
	}
}

之后我们就来设置棋盘的格式,把它弄的好看一点,而不是一片空白。

9e8d7f0c75014dfb9ef5b9a871f31fba.png

 

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

}

代码写好后,就变成了这样

eff027cd89ff4c03836caf529e019575.png

但是这个代码只能实现3*3的棋盘,如何提升代码的通用性呢? 我们可以这样 

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

这样,也能实现五子棋的棋盘了。

 102d2b354a2f45b89d16ebde86f43448.png171a47c0ffa64a388547a3a72086a3a2.png

3.玩家走

棋盘设置好后,就该下棋了。我们先让玩家先走。

首先要想明白的是数组下标和玩家输入的坐标并不一样,玩家输入1,1代表的是数组下标0,0这个地方很重要不要搞混了。

然后坐标输入后,就直接把棋子落入坐标吗?

NO!

我们还得判断玩家的坐标在不在我这个棋盘上,还得判断这个坐标有没有被占用,这两个判断完后,如果都满足才能顺利落子。否则,我就要回到输入,让玩家重新输入坐标,而这是不是又是一个循环呢?循环结束的条件就是顺利落子的条件。

玩家的棋子我们用  表示

void pplay(char board[ROW][COL], int r, int c)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家走->");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
				printf("被占用,请重新输入\n");
		}
		else
			printf("坐标非法,请重新输入\n");
	}
		
}

 这样,玩家走的代码也完成了。

4.电脑走

一样的先来捋捋思路。电脑下棋我们人为不能干涉,应该就是随机走了吧,既然这样,我们就要用到rand函数,而随机的依据我们用时间戳,要对rand函数进行初始化。

而电脑落子也得考虑该地方有没有被占用和坐标合法问题。但是这里的坐标合法问题我们在生成坐标的时候就可以解决,我们用生成的随机数%3,这样它的坐标就在0-2之间,是不是永远就合法了。而不满足的话,和上面一样,是不是还得用循环,直到坐标合法。

最后,最重要的一点,我们还是得想明白数组下标和我们日常生活中的坐标的区别,电脑落子用的是数组下标,所以这里和玩家落子的下标就有差异了。来看看代码。

电脑下棋我们用 # 来表示

void cplay(char board[ROW][COL], int r, int c)
{
	int x = 0;
	int y = 0;
	printf("电脑走->\n");
	while (1)
	{
		 x = rand() % r;
		 y = rand() % c;
		if (board[x][y] == ' ')
			{
				board[x][y] = '#'; //注意和玩家走的时候下标的区别哦
				
				break;
			}
	}
}

二.判断胜平负逻辑

电脑和人的下棋逻辑我们写完了,那棋盘是有限的,也存在胜负。所以我们每下一次棋就得判断是否有输赢,没有就继续,反之则游戏结束。

而判断胜的条件不就是3颗棋子在一条线上且3颗棋子不能是空格吗,所以三行,三列,两条对角线都存在胜的情况,我们需要分开来判断。最后我们只需要返回3颗相等棋子中的1颗棋子就好,看看是电脑胜还是玩家胜。

当然也存在另一种情况,就是棋盘下满了,还未分出胜负,我们就要写一个判断是否平局的函数。

在这个判断平局的函数中,实现逻辑很简单,就遍历一下棋盘,看看是否存在空格,存在空格,说明还不是平局,游戏继续,反正,则游戏结束,返回Q。

最后,如果没有胜负且不为平局,游戏就继续,返回C。

int isfull(char board[ROW][COL], int r, int c)
{
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < c; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
		return 1;
}


int iswin(char board[ROW][COL], int r, int c)
{
	int i = 0;
	int j = 0;
//行
	for (i = 0; i < r; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			return board[i][0];
		
	}
//列
	for (j = 0; j < c; j++)
	{
		if (board[0][j] == board[1][j] && board[2][j] == board[1][j] && board[1][j] != ' ')
			return board[0][j];
	}

//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
		return board[2][0];
	
	if(isfull(board, r, c)==1)
	return 'Q';   //平局
	return 'C';   //游戏继续
}

来看看外部的判断逻辑。 

首先玩家下棋,电脑下棋,判断输赢是一个循环,一样需要一个循坏来实现,当ret为不为C的时候,代表游戏已经结束了,就跳出循环。然后再判断是胜 是负 还是平局。

void game()
{
	int ret = 0;
	char board[ROW][COL];
	init(board, ROW, COL);
	print(board, ROW, COL);
	while (1)
	{
		pplay(board, ROW, COL);
		print(board, ROW, COL);
		ret=iswin(board, ROW, COL);
		if (ret != 'C')
			break;
		cplay(board, ROW, COL);
		print(board, ROW, COL);
	    ret=iswin(board, ROW, COL);
		if (ret != 'C')
			break;
		
	}
	if (ret == '#')
		printf("电脑赢\n");
	else if (ret == '*')
		printf("玩家赢\n");
	else
		printf("平局\n");


}

三.完整代码(采用分模块)

1.头文件部分

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void menu();
void init(char board[ROW][COL],int r,int c);
void print(char board[ROW][COL], int r, int c);
void pplay(char board[ROW][COL], int r, int c);
void cplay(char board[ROW][COL], int r, int c);
int  iswin(char board[ROW][COL], int r, int c);

 2.游戏实现逻辑

#define  _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
	printf("\n");
	printf("|--欢迎来到三子棋--|\n");
	printf("|******************|\n");
	printf("|******1.play******|\n");
	printf("|******0.exit******|\n");
	printf("|------------------|\n");
}

void init(char board[ROW][COL], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		for (j = 0; j < c; j++)
		{
			board[i][j] = ' ';
		}
	}
}

//void print(char board[ROW][COL], int r, int c)
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < r; i++)
//	{
//		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//		if(i<r-1)
//		printf("---|---|---\n");
//	}
//
//}
void print(char board[ROW][COL], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		for (j = 0; j < c; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < c - 1)
				printf("|");
		}
		printf("\n");
		
		if (i < r - 1)
		{
			for (j = 0; j < r; j++)
			{
				printf("---");
				if (j < c - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void pplay(char board[ROW][COL], int r, int c)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家走->");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
				printf("被占用,请重新输入\n");
		}
		else
			printf("坐标非法,请重新输入\n");
	}
		
}

void cplay(char board[ROW][COL], int r, int c)
{
	int x = 0;
	int y = 0;
	printf("电脑走->\n");
	while (1)
	{
		 x = rand() % r;
		 y = rand() % c;
		if (board[x][y] == ' ')
			{
				board[x][y] = '#';
				
				break;
			}
	}
}
int isfull(char board[ROW][COL], int r, int c)
{
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < c; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
		return 1;
}

int iswin(char board[ROW][COL], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			return board[i][0];
		
	}
	for (j = 0; j < c; j++)
	{
		if (board[0][j] == board[1][j] && board[2][j] == board[1][j] && board[1][j] != ' ')
			return board[0][j];
	}


	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
		return board[2][0];
	
	if(isfull(board, r, c)==1)
	return 'Q';
	return 'C';
}

 3.测试部分

#define  _CRT_SECURE_NO_WARNINGS4
#include"game.h"
void game()
{
	int ret = 0;
	char board[ROW][COL];
	init(board, ROW, COL);
	print(board, ROW, COL);
	while (1)
	{
		pplay(board, ROW, COL);
		print(board, ROW, COL);
		ret=iswin(board, ROW, COL);
		if (ret != 'C')
			break;
		cplay(board, ROW, COL);
		print(board, ROW, COL);
	    ret=iswin(board, ROW, COL);
		if (ret != 'C')
			break;
		
	}
	if (ret == '#')
		printf("电脑赢\n");
	else if (ret == '*')
		printf("玩家赢\n");
	else
		printf("平局\n");


}
int main()
{
	srand(time(NULL));
	int imput = 0;
	do {
		menu();
		printf("请选择->");
		scanf("%d", &imput);
		switch (imput)
		{
		case 1:
			printf("\n开始游戏!\n\n");
			game();
			break;
		case 0:
			printf("再见\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (imput);

}

这样一个三子棋就完成了! 

 

 

 

 

 

 

 

 

 

 

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
五子棋是一种相对简单的棋类游戏,可以用C语言实现人机对战的功能。 首先,我们需要定义一个棋盘的二维数组来表示游戏界面,可以选择一个15×15的大小。用1代表玩家落子的地方,用2代表电脑落子的地方,用0代表空白的地方。 接下来,需要编写一个函数来打印当前的棋盘状态。可以使用循环来遍历棋盘数组,并根据不同的值输出对应的符号,比如打印X表示玩家落子,打印O表示电脑落子,打印空格表示空白的位置。 然后,需要编写一个函数来实现玩家的落子功能。可以通过向控制台读取玩家的输入来确定落子的位置,然后将相应的棋盘数组位置修改为1。 接着,需要编写一个函数来实现电脑的落子功能。可以使用一种简单的算法来确定落子的位置,比如随机选择一个空白位置来落子,并将对应的棋盘数组位置修改为2。 最后,还需要编写一个函数来检查游戏是否结束。可以通过遍历棋盘数组来检查是否有五个相连的棋子。可以编写多个检查函数,分别检查横向、纵向、左上到右下、右上到左下四个方向是否存在五连子。 在主函数中,可以通过循环来控制游戏的进行,每个循环中先打印当前的棋盘状态,然后让玩家落子,再检查游戏是否结束,如果没有结束则让电脑落子,再次检查游戏是否结束。 以上就是用C语言实现简易五子棋人机对战的基本思路,可以根据需要进行进一步的功能扩展和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JJY_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值