C++编写的2048小游戏

C++编写的2048小游戏

核心算法:

思考:当你按下左键时,如何让每一个行的数进行向左靠拢并叠加呢?
就一行来讲:每次我们都要从左向右判断相邻的两个数,是否相等,但是可能这两个数中间有一个是空白(也就是0)。所以首先我们先得把两个不等于0的数拉到左边来,如果相等就相加赋两个数中左边的,右边的那个数就赋为0。然后继续寻找下一对数。从下图来看,每行得判断3对数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以下是当按下左键的代码(其他方向类似):

void mvdata(char a, int (*p)[4])  //靠拢叠加
{
	int i,j,k;   ///i是行,j是列
	if(a==75 || a=='a') //左
	{
		for(i=0;i<4;i++)   
		   for(j=0;j<3;j++)
		   {
				if(p[i][j]==0)  //把第一个数拉左边来
					for(k=j+1;k<4;k++)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					}
				j++;
				if(p[i][j]==0)  //把第二个数拉左边来
					for(k=j+1;k<4;k++)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					}
				j--;
				if(p[i][j]==p[i][j+1])
				{
					p[i][j]*=2;
					p[i][j+1]=0;
				}
		   }
	}
}

如果你以上的看懂了,就可开始动手了。
以下是整个游戏的代码(简单写了下):

#include <iostream>
#include <ctime>   //设置随机数的time
#include <conio.h>   //使用_kbhi(),_get函数ch()
#include <iomanip>  //使用函数stew()控制数据输出宽度。
#include <windows.h>  //指定位置输出
using namespace std;
void gotoxy(int x,int y) //将光标移动到坐标为(x,y)的地方
{
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
HANDLE hConsoleOut;
hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsoleOut,&csbiInfo);
csbiInfo.dwCursorPosition.X = x;
csbiInfo.dwCursorPosition.Y = y;
SetConsoleCursorPosition(hConsoleOut,csbiInfo.dwCursorPosition);
}
void HideCursor() // 用于隐藏光标
{
CONSOLE_CURSOR_INFO cursor_info = {1, 0};  // 第二个值为0表示隐藏光标
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
/*
复制数组,并判断数组前后变化了没
*/
int change(const int (*p)[4],const int (*q)[4])
{
	int i,j;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
		{
			if(p[i][j]!=q[i][j])
				return 1;  //改变返回1(真)
		}
	return 0;   //没变返回0(假)
}
void copyroom(int (*p)[4],const int (*q)[4])
{
	int i,j;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
			p[i][j]=q[i][j];
}
/*
随机给空的地方出现2或4
*/
int getrand(void)
{
	srand((unsigned)time(NULL));
	return rand();
}
int getrandnumber(void)
{
	return getrand()%2 ? 2 : 4 ;
}
int srandnumber(int (*p)[4])
{
	int i,j;
	while(1)
	{
		for(i=0;i<4;i++)
			for(j=0;j<4;j++)
			{
				if( p[i][j]==0 ) //若为空白
					if(rand() % 3==0)  //且随机数是16的倍数 //考虑到程序运行的数据不大所以可以这么搞
					{
 						p[i][j]=getrandnumber();
						 return 0;   //结束
					}
			}
	}
}
/* 
接收敲击键盘的上下左右键,并作出相应的反应
*/
void mvdata(char a, int (*p)[4])  //靠拢叠加
{
	int i,j,k;   ///i是行,j是列
	if(a==75 || a=='a') //左
	{
		for(i=0;i<4;i++)   
		   for(j=0;j<3;j++)
		   {
				if(p[i][j]==0)  //把第一个数拉左边来
					for(k=j+1;k<4;k++)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					}
				j++;
				if(p[i][j]==0)  //把第二个数拉左边来
					for(k=j+1;k<4;k++)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					}
				j--;
				if(p[i][j]==p[i][j+1])
				{
					p[i][j]*=2;
					p[i][j+1]=0;
				}
		   }
	}
	if(a==77 || a=='d')  //右
	{
		for(i=0;i<4;i++)
		   for(j=3;j>0;j--)
		   {
				if(p[i][j]==0)  //把数拉右边来
					for(k=j-1;k>=0;k--)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					} 
				j--;
				if(p[i][j]==0)  //把数拉右边来
					for(k=j-1;k>=0;k--)
					{
						if(p[i][k]!=0)
						{
							p[i][j]=p[i][k];
							p[i][k]=0;
							break;
						}
					} 
				j++;
				if(p[i][j]==p[i][j-1])
				{
					p[i][j]*=2;
					p[i][j-1]=0;
				}
		   }
	}
	if(a==72 || a=='w')  //上
	{
		for(j=0;j<4;j++)
			for(i=0;i<3;i++)
			{
				if(p[i][j]==0)   //把数拉上边来
					for(k=i+1;k<4;k++)
					{
						if(p[k][j]!=0)
						{
							p[i][j]=p[k][j];
							p[k][j]=0;
							break;
						}
					}
				i++;
				if(p[i][j]==0)   //把数拉上边来
					for(k=i+1;k<4;k++)
					{
						if(p[k][j]!=0)
						{
							p[i][j]=p[k][j];
							p[k][j]=0;
							break;
						}
					}
				i--;
				if(p[i][j]==p[i+1][j])
				{
					p[i][j]*=2;
					p[i+1][j]=0;
				}
			}
	}
	if(a==80 || a=='s')  //下
	{
		for(j=0;j<4;j++)
	    	for(i=3;i>0;i--)
			{
				if(p[i][j]==0) //把数拉下边来
					for(k=i-1;k>=0;k--)
					{
						if(p[k][j]!=0)
						{
							p[i][j]=p[k][j];
							p[k][j]=0;
							break;
						}
					}
				i--;
				if(p[i][j]==0) //把数拉下边来
					for(k=i-1;k>=0;k--)
					{
						if(p[k][j]!=0)
						{
							p[i][j]=p[k][j];
							p[k][j]=0;
							break;
						}
					}
				i++;
				if(p[i][j]==p[i-1][j])
				{
					p[i][j]*=2;
					p[i-1][j]=0;
				}
			}
	}
}
/*
判断输赢
*/
int score(const int (*p)[4])  //分数
{
	int i,j,score=0;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
		{
			score=(score<p[i][j]? p[i][j]:score);
		}
    return score;
}
int judgelose(const int (*p)[4])  //判断输了没
{
    int i,j,score=0;
	for(i=0;i<4;i++)
	   for(j=0;j<3;j++)
	   {
		   if(p[i][j]==p[i][j+1] || p[i][j]==0 || p[i][j+1]==0)
			   return 0;
	   }
	for(j=0;j<4;j++)
		for(i=0;i<3;i++)
		{
		   if(p[i][j]==p[i+1][j] || p[i][j]==0 || p[i+1][j]==0)
				return 0;    //是假输
		}
	return 1;   ///是真输
}
int judgewin(const int (*p)[4])  //判断赢了没
{
	if(score(p)==2048)
		return 1; // 是真赢
	return 0; //是假赢
}
void printmap(int (*p)[4])    //打印地图数据
{
	int i,j;
	gotoxy(0,0);
	cout << "┌-----┬-----┬-----┬-----┐"<< endl;
	for(i=0;i<4;i++)
	{
		cout << "│";
		for(j=0;j<4;j++)
		{
			cout << setw(5) << p[i][j] << "│";
		}
		cout << endl;
		if(i!=3)
		{
			cout << "├-----┼-----┼-----┼-----┤" << endl;
		}
	}  
		cout << "└-----┴-----┴-----┴-----┘"<< endl;
	cout << "分数: " << score(p) << endl;
}
int main(){
	char kbht;
    int a[4][4]={0},b[4][4]={0};  //定义数组
	srandnumber(a);  //先给他随机两个数
	srandnumber(a);
	copyroom(b,a);
	printmap(a);
	HideCursor();
    while(1)
	{
		if(_kbhit())   //获取键盘上按键的情况
		{
			kbht=_getch();
			mvdata(kbht,a);
			if(change(a,b))
			{
				srandnumber(a);
				printmap(a);
				if(judgewin(a))
				{
					 cout << "好吧,你赢了,算你厉害!" << endl;
					 break;
				}
				if(judgelose(a))
				{
					 cout << "你输了,再接再厉吧!" << endl;
					 break;
				}
			}
			copyroom(b,a);
		}
	}
	return 0;
}

新手小白刚学C++,有什么建议话,欢迎各位在以下给我留言。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值