三子棋(五子棋)可拓展棋盘版

本文以五子棋为例,详细介绍了如何制作一个简单的棋类游戏。从创建游戏菜单,设定先手后手,初始化棋盘,到生成棋盘界面,模拟玩家和电脑的下棋过程,再到判断胜负的算法,每一环节都有清晰的代码解释。此外,还讨论了随机数生成和游戏循环的实现,以及如何根据游戏结果进行分支处理。
摘要由CSDN通过智能技术生成

(我们这里以五子棋为例子,具体的值可以自行修改哦)

1.要做一个下棋的小游戏,首先先做一个简陋的游戏菜单界面哈哈=)

void menu()//游戏菜单界面
{
	printf("****************************************************\n");
	printf("*********输入1开始游戏     输入0退出游戏************\n");
	printf("****************************************************\n");
}

 2.既然模拟下棋的过程,就要有先后手的区别,因为我们是高贵的真人玩家(bushi),所以由我们决定先后手

printf("请选择先手还是后手:(1为先手,2为后手)\n");
	scanf("%d", &n);
	system("cls");  //清屏操作 为了界面更好看=)
	if (n == 1) {
		while (1) {    //用while(1)的原因后面会提到
			;//过程     
		}
	}
	if (n == 2) {
		while (1) {
			;//过程
		}
	}

3.在游戏开始之前,我们还得初始化一下棋盘上的棋子,方便后续的操作

void init(int m, int n)   //初始化为空格
{
	int i = 0, j = 0;
	for (i = 0; i < m; i++)
	{
		for (j = 0; j < n; j++)
		{
			a[i][j] = ' ';
		}
	}
}

原因在后面会说到(说是后面,其实就在下一点)

4.. 之后就要生成我们的棋盘

(我做了两个版本的棋盘)        虽然好像没什么意义,但是好看捏=)

 

//井字形棋盘
void display( int m, int n)
{
	int i = 0,j=0;
	for (i = 0; i < m; i++)//以给定的行数 重复打印
	{
		//一行的内容
		for (j = 0; j < n; j++)
		{
			printf(" %c ", a[i][j] );
			if (j < n - 1)
				printf("|");
		}//打印出有数据的一行
			printf("\n");
		if (i < h - 1)
		{
			for (j = 0; j < n; j++)
			{
				printf("---");
				if (j < n - 1)
					printf("|");
			}//打印出分割行
		}
		printf("\n");
	}
}
//封闭型棋盘
void display(int m, int n)
{
	int i = 0, j = 0;
	for (i = 0; i < m + 1; i++)//以给定的行数 重复打印
	{
		for (j = 0; j < n + 1; j++)
		{
			printf("|");
			if (j < n)
			{
				printf("---");
			}

		}//打印出分割行
		printf("\n");
		if (i < n)
		{//一行的内容
			for (j = 0; j < n + 1; j++)
			{
				printf("|");
				if (j < n)
					printf(" %c ", a[i][j]);

			}//打印出有数据的一行
		}
		printf("\n");
	}
}
  • 这些线线的打印就看你的需求了,使用for循环实现
  • 这里就用到了我们前一步的初始化捏,不要想当然的觉得直接打印空格就好了哦,因为我们落子的过程就是给a数组赋值

 5.我们先模拟玩家先手的情况

(图为玩家已经下了第一步)

*是玩家棋子,-是电脑棋子

void playermove(int m, int n) {
	printf("玩家下棋\n");
	printf("请输入你要下棋的位置:\n");
	display(h, l);
	int q = 0, w = 0;
	while (1) {
		scanf("%d%d", &q, &w);  
		if ((q >= 1 && q <= m) || (w >= 1 && w <= n)) {     //对于玩家来说
			if (a[q - 1][w - 1] == ' ') {     //对于电脑,坐标应-1
				a[q - 1][w - 1] = '*';
				system("cls");
				break;
			}
			else {
				printf("该位置被占用,请重新输入\n");
			}
		}
		else {
			printf("该位置不存在,请重新输入\n");
		}
	}
}

 这是玩家进行下棋的代码

(需要进行对输入坐标的判断)

  1. 输入正确,进行落子,并退出该while循环
  2. 输入的坐标已经被占用或超出范围,进行提示,并提醒重新输入(通过while(1)实现重新输入的操作)

 6.玩家落子后,该电脑进行(但电脑不能无端落子,需要生成坐标)

为了保证游戏的公平性,使用随机数生成

//随机在空处下 
void computermove(int m, int n) {
	system("cls");
	printf("电脑下棋\n");
	int q = 0, w = 0;
	while (1) {
		q = rand() % m;       //用随机数生成坐标
		w = rand() % n;
		if (a[q - 1][w - 1] == ' ') {      //下标要-1哦
			a[q - 1][w - 1] = '-';
			break;
		}
	}
}
  1. rand()函数生成随机数,其头文件为<stdlib.h>       (这个绿色真好看捏)
  2. 用rand()生成随机数时,需要和srand()函数配套使用
  3. srand()是一个随机数生成器(即设置一个随机起点),其头文件为<stdlib.h>,其括号内为unsigned整型,所以需要强制类型转换(我们得到的是整型)
  • 其实我们将它称为随机数是不够准确的,其实是伪随机数,是一串已经生成好的数字序列
  • 当你不设置随机数生成器时,得到的数字序列将会相同,因为系统会自动给你配置一个srand(1)
  • 若为srand(1),则会固定出现某个不变的数字,因为其应该出现变量的位置上是1,一个固定的数字决定了这串数字有固定的起点,那么你得到的数字序列为同一串,即每次打印出来的结果都相同
  • (就我的理解来说,应该是srand()从无限个门里选取某一个门作为起点,每个门里都有一串没有规律的数字序列,因此若是1,即你一直选取的都是序号为1的门,所以你得到的数字相同)(哈哈,个人理解,轻喷,本人只是一个可怜弱小的大一学生)

  1. 所以我们应该自己设置一个一直会变化的变量,使用时间是最稳妥和最常用的
  2. 我们一般能获取到的就是系统时间,使用time()函数来获得,其头文件为<time.h>,其括号内需要一个指针,我们一般使用NULL(因为我们不需要这个指针出现什么效果)
  3. time()得到的值被称为时间戳,是以秒为单位,用1970年1月1日0点减去现在的时间,这样我们可以保证我们每次得到的值都是不同的,即起点不同
  • 我去查了查,为啥非得是1970年1月1日0点

 因为用32位来表示时间的最大间隔是68年,而最早出现的UNIX操作系统考虑到计算机产生的年代和应用的时限综合取了1970年1月1日作为UNIX TIME的纪元时间(开始时间)

了解就好,如果有人问你,就可以浅浅装个b啦=)帮别人答疑解惑啦=)

 可恶,扯远了,看我怎么圆回来

  1. 前面不是在聊随机数嘛,随机数也是有范围的,rand()的范围为0-x7fff(32767)
  2. 如果我们要生成给定范围的随机数,假设你要生成[n,m]的随机数,可以用rand() % (m-n+1)+n

7.然后就是最最最最最.......(省略10086个最)重要的了!!!判断胜负!

下棋嘛,也就那么几种获胜形式,要么一横排,要么一竖列,要么对角线(当然憋忘了对角线有两种)

废话不多说,直接看代码叭=)

int win(int m, int n) {
	//玩家赢,* 
	//电脑赢,-
	//平局,p
	int i = 0, j = 0;
	int count = 0;
	for (i = 0; i < m; i++) {
		for (j = 0; j < n - 1; j++) {
			if (a[i][j] == a[i][j + 1] && a[i][j] != ' ' ) { //两个为一组比较//横排相等
				count++;
			}
		}
		if (count == m-1) {     //因为两个一组,所以-1
			return a[i][j];
		}
		count = 0;
	}
	for (j = 0; j < n; j++) {
		for (i = 0; i < m - 1; i++) {
			if (a[i][j] == a[i + 1][j] && a[i][j] != ' ') {    //竖列相等
				count++;
			}
		}
		if (count == n-1 ) {
			return a[i][j];
		}
		count = 0;
	}
	j = 0;
	for (i = 0; i < m-1; i++) {
		if (a[i][j] == a[i + 1][j + 1] && a[i][j] != ' ') {    //"\"对角线
			count++;
		}
		j++;
	}
	if (count == m-1) {
		return a[i][j];
	}
	count = 0;
	j = j - 1;
	for (i = 0; i < m-1; i++) {
		if (a[i][j] == a[i + 1][j + 1] && a[i][j] != ' ' ) {     //"/"对角线
			count++;
		}
		j--;
	}
	if (count == m-1 ) {
		return a[i][j+1];
	}
	if (full(h, l) == 1) {        //判断是否格子被占满,若未出胜负前格子已满,即为平局
		return 'p';  
	}
	return 'g';     //都不满足就继续,"go"
}
  • 就按照胜利的条件,分为三大块的判断,第三块的又分为俩小块
  • 我使用的是:如果两个格子内的字符如果相等就+1,然后如果等于棋盘的行数-1(两个一组哦!所以-1)就是胜利(别忘了排除两个字符都是空格的情况)
  • 最后,还得判断棋盘上是否被占满了,原因注释里有哦

int full(int m, int n) {   //判断是否满
	int i = 0, j = 0;
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			if (a[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}
  • 如果没满就返回0,满了就返回0,并且win()返回'p'(注意哦,咱们win()不是有返回值吗,在外层函数里就需要用这个返回值来分成不同的情况
  • 其中不是有return a[i][j] 吗,这里就是比较巧妙的一点了,我们可以直接返回满足占满一行或一列或对角线的该字符,用if来分支时,就可以用if(接收返回值的变量=='*'),这样就是玩家赢,因为玩家使用的是*棋子;电脑赢就是if(接收返回值的变量=='-'),我们设置的电脑棋子就是-哦 =)
  • (当然这个代码电脑赢很难,因为对面没有思考,只是将按生成的随机数落子)

8.游戏的主体内容实现就已经完成了,之后就是将返回的字符进行分支处理

我直接按代码执行的顺序贴代码叭

int main()//大框架
{
	test();
	return 0;
}
void test()//游戏流程
{
	int a;
	menu();
	do
	{
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			printf("开始我们的游戏吧!\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新输入\n");
		}
	} while (a);
}
void game()//游戏实现
{
	srand((unsigned int)time(NULL));
	init(h, l);//初始化棋盘(放入空格)
	int n = 0;
	char e = 0;
	//游戏过程
	printf("请选择先手还是后手:(1为先手,2为后手)\n");
	scanf("%d", &n);
	system("cls");
	if (n == 1) {
		while (1) {
			playermove(h, l);
			e = win(h, l);
			if (e != 'g') {
				break;
			}
			computermove(h, l);
			display(h, l);
			e = win(h, l);
			if (e != 'g') {
				break;
			}
		}
	}
	if (n == 2) {
		while (1) {
			computermove(h, l);
			display(h, l);
			e = win(h, l);
			if (e != 'g') {
				break;
			}
			playermove(h, l);
			display(h, l);//打印棋盘
			e = win(h, l);
			if (e != 'g') {
				break;
			}
		}
	}
	if (e == '*') {
		display(h, l);
		printf("恭喜你赢得胜利\n");
		printf("是否要重新开始:");
	}
	if (e == '-')  {
		display(h, l);
		printf("很遗憾你输了\n");
		printf("是否要重新开始:");
	}
	if (e == 'p') {
		display(h, l);
		printf("本局为平局\n");
		printf("是否要重新开始:");
	}
}
  • do while循环可以通过你玩完一局后输入的数字进行判断,如果是1就再来一局,0就退出游戏
  • 在适当的地方使用清屏,可以让执行过程更加美观(但我调整不好,所以就只保留了一个,呜呜) 

system("cls")可以实现清屏,其头文件是<stdlib.h>

9.其他的

我写的多文件形式,记得要用"   "引用自定义的头文件哦

#define h 5
#define l 5
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

char a[h][l];//建立棋盘信息
void init(int m, int n);
void display(int m, int n);
void playermove(int m, int n);
void computermove(int m, int n);

int win(int m, int n);
int full(int m, int n);
  • 这是我设置的头文件,标题说的可拓展就是用宏定义实现的,你可以随意改h和l的值哦=),改成几就是几子棋
  • 我test.c中放的就是8里的代码,是游戏的整体框架,虽然套了好几层
  • game.c顾名思义,就是实现游戏内容的文件

完美落幕啦~~~撒花~~~

感谢您的观看!  =)

这是孩子第一篇博客,有不妥之处可以直接告诉我哦,我会很感谢您的建议(鞠躬)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值