C语言界面实现2048小游戏

这是我在大一第二学期(两年前)为了参加比赛,自学后写的一个Demo,拿出来和大家分享一下,代码为两年前的代码,未改动,优化以及各式可能很一般,请见谅。


#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#define N 4//方阵边长 
#define WIN 2048//游戏获胜目标 
void output(int (*a)[N]){//输出4*4表格, 
	int i,j;
		printf("\n");
		printf("┏━━━━┳━━━━┳━━━━┳━━━━┓");//顶边框 
		printf("\n");
	for(i=0;i<N;i++){printf("┃") ;
		for(j=0;j<N;j++){
			if(a[i][j]==0) printf("    ┃");//如果数值为零则输出空白 
			else  printf("%4d┃",a[i][j]);
		}
		if(i!=3)
		printf("\n┣━━━━╋━━━━╋━━━━╋━━━━┫\n");//层边框 
		else 	printf("\n┗━━━━┻━━━━┻━━━━┻━━━━┛\n");//底边框 
	}
}  
int sj24(){//获取随机数2或4 
	int s[8]={2,2,2,2,2,2,2,4},i,j;//以概率7:1建立2和4的随机数种子 
	srand((unsigned)time(NULL));
	i=(rand())%8;//以时间为种子得到0~7的随机数 
	return s[i];
}
int input(){//输入上下左右指令控制游戏 
	int m;
	if(getch()==0xE0){ //对键入的命令进行识别 
		switch(getch()){//十位1表示水平移动2表示竖直移动,各位1表示向小坐标移动2表示向大坐标移动 
			case 72: return 21;break;//输入上 
			case 80: return 22;break;//输入下 
			case 75: return 11;break;//输入右 
			case 77: return 12;break;//输入左
			default:{//若命令不符合要求,运用递归重新得到命令 
				printf("请输入正确的指令!(~ ̄(OO) ̄)ブ\n");
				return input();	
			}
	}
}
	else {//若命令不符合要求,运用递归重新得到命令 
		printf("请输入正确的指令!(~ ̄(OO) ̄)ブ\n\n");
		return input();
		}
}
void move(int (*a)[N]){ //通过调用input函数得到正确的命令,根据命令移动数据 
	int x,i,j,k,s[N][N],t=0;
 	x=input();
 	for(i=0;i<N;i++){
		for(j=0;j<N;j++) s[i][j]=a[i][j];//拷贝移动前方阵方便以后检查 
	}
 	if(x/10==1){//水平移动 
 		if(x%10==1){//向小坐标移动 
		 	for(i=0;i<N;i++){for(k=0;k<3;k++){//  核心算法介绍 
		 		for(j=N-1;j>0;j--){           //第一步,先将一排数据重后往前一个个向前推(除去前面和中间的0) 
 					if(a[i][j-1]==0) {        //为确保移动完全经推理最多3次完成所有移动所有执行3次该算法 
					a[i][j-1]=a[i][j];        //第二步,将相邻两两相同的数相加赋值前者后者赋0 
 					a[i][j]=0;                // 第三部,重复第一步操作去除新产生的0,总操作完成 
 					}                         //PS:所有方向算法原理相同 
 	     		}
 	     		}
		 		for(j=0;j<N-1;j++){
 					if(a[i][j]==a[i][j+1]) {
						a[i][j]=a[i][j]+a[i][j+1];
						a[i][j+1]=0;
					}
				}
		 		for(k=0;k<3;k++){
		 		for(j=N-1;j>0;j--){
 					if(a[i][j-1]==0) {
					a[i][j-1]=a[i][j];
 					a[i][j]=0;
 					}
 	     		}
 	     		}
		 	}	 
		 }
		 else{//向大坐标移动 
		 	for(i=0;i<N;i++){for(k=0;k<3;k++){
		 		for(j=0;j<N-1;j++){
 					if(a[i][j+1]==0) {
					a[i][j+1]=a[i][j];
 					a[i][j]=0;
 					}
 	     		}
 	     		}
				for(j=N-1;j>0;j--){
 					if(a[i][j]==a[i][j-1]) {
						a[i][j]=a[i][j]+a[i][j-1];
						a[i][j-1]=0;
					}
				}
		 		for(k=0;k<3;k++){
		 		for(j=0;j<N-1;j++){
 					if(a[i][j+1]==0) {
					a[i][j+1]=a[i][j];
 					a[i][j]=0;
 					}
 	     		}
 	     		}
		 	}	 
		 }
	 }
 	else{//竖直移动 
 		if(x%10==1){//向小坐标移动 
		 for(i=0;i<N;i++){for(k=0;k<3;k++){
				for(j=N-1;j>0;j--){
 					if(a[j-1][i]==0) {
					a[j-1][i]=a[j][i];
 					a[j][i]=0;
 					}
 	     		}
 	     		}
				for(j=0;j<N-1;j++){
 					if(a[j][i]==a[j+1][i]) {
						a[j][i]=a[j][i]+a[j+1][i];
						a[j+1][i]=0;
					}
				}
		 		for(k=0;k<3;k++){
				for(j=N-1;j>0;j--){
 					if(a[j-1][i]==0) {
					a[j-1][i]=a[j][i];
 					a[j][i]=0;
 					}
 	     		}
 	     		}	
			}
		 }
		 else{//向大坐标移动 
		 	for(i=0;i<N;i++){for(k=0;k<3;k++){
		 		for(j=0;j<N-1;j++){
 					if(a[j+1][i]==0) {
					a[j+1][i]=a[j][i];
 					a[j][i]=0;
 					}
 	     		}
 	     		}
				for(j=N-1;j>0;j--){
 					if(a[j][i]==a[j-1][i]) {
						a[j][i]=a[j][i]+a[j-1][i];
						a[j-1][i]=0;
					}
				}
		 		for(k=0;k<3;k++){
		 		for(j=0;j<N-1;j++){
 					if(a[j+1][i]==0) {
					a[j+1][i]=a[j][i];
 					a[j][i]=0;
 					}
 	     		}
 	     		}
		 	}
		 }
	 }
	 for(i=0;i<N;i++){//检查是否为有效移动 
		for(j=0;j<N;j++) {
			if (s[i][j]!=a[i][j]) t=1;
		}
		}
		if(t){
			begin(a);	
			Sleep(60);//为让玩家知道移动后随机数出现位置,让其延迟出现 
			get(a);	
			begin(a);
		}  
		else printf("选择其他方向试试(¬_¬)"); 
}
void get(int (*a)[N]){//在4*4表格中空板位置随机获得数字 
	int i,j;
	srand((unsigned)time(NULL));
	do{
			i=(rand())%4;
			j=(rand())%4;	
	} while(a[i][j]!=0); 
	 a[i][j]=sj24();
}  
void begin(int (*a)[N]){//清屏并打印开头 
	system("cls"); 
	printf("        小游戏2048\n\n  ");
	printf("   键入上下左右控制\n");
	output(a);
} 
int test(int (*a)[N]){//判断是否游戏完成 
	int i,j,k=0,m=0,n=0;
		printf("\n");
	for(i=0;i<N;i++){
		for(j=0;j<N;j++){
			if(a[i][j]==0)m=1;//检查方阵中是否有0 
			if(a[i][j]==WIN)k=1; //检查方阵中是否有目标数字 
		}
	}
	if (k){//如果发现目标数字判定游戏获胜 
		printf("YOU WIN! \(^o^)/YES!"); 
		return 0;
	}
	else{
		if(!m){//如果方阵中无0且无相邻数字相等则判定游戏失败,反之游戏继续 
		 	for(i=0;i<N;i++){
				for(j=0;j<N-1;j++)
					if(a[i][j]==a[i][j+1]||a[j][i]==a[j+1][i]) n=1;
			}
	   	if(n) return 1;
		else{
			printf("GAME OVER!〒▽〒");
			return 0;
			}
		}
		else return 1;   
	}		 
}
void main(){
	 int a[N][N]={0};
	 get(a);get(a);begin(a);//起始时方阵有两个随机数 
	while(test(a)) move(a); //只有通过tset函数检查才能继续游戏 
} //谢谢 

原说明文档:

作品名:小游戏2048

使用语言:C语言

使用编译器:DEV-C++

游戏说明:《2048》是一款比较流行的数字游戏,最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块(2或4),相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048

程序设计思路:

   在程序编写之前我只知道游戏的规则和对游戏把玩的经验。后来对游戏原理进行思考,大体的得到了程序编写的方向。

首先我需要一个4*4的表格来填放数字,可用二维数组来表达,用一个4*4的二维数组,初值设定为0。

开始在4*4的表格中随机出现两个2或4的随机数,为保证游戏难度正常出现2的概率应大于出现4的概率(P2:P4=7:1),然后键入一次方向键后进行相应移动、合并。完成移动后在表格中空白位置出现一个2或4的随机数。

游戏胜负判定:若数字“2048”出现则为获胜并输出“YOU WIM!”,若数字填满方格且每个数字无相邻相等(即不可移动)则为失败并输出“GAME OVER!”

核心算法(移动合并):第一步,先将需要操作的一行数据的非零数字向需移动方向靠齐(去0)。第二步,将相邻相等数字相加,靠近需移动的一个赋二者的和另一个赋0,若有连续三个数字相等,操作前两个。若前两个后两个均可合并,可同时操作。第三步,重复第一步操作,去除第二步新产生的0。

算法细节详见源文件代码及注释。

程序完成截图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值