C++编写的2048小游戏

本文介绍了一个用C++编写的2048小游戏的实现细节,重点讲解了游戏的核心算法,包括如何通过键盘输入控制数字方块的移动、合并以及随机生成新数字的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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++,有什么建议话,欢迎各位在以下给我留言。

C++编写2048小游戏的键盘控制模块,通常会涉及到事件监听和按键映射。首先,你需要包含一些头文件,如`#include <SFML/Graphics.hpp>`,以利用SFML库处理窗口和键盘输入。 ```cpp #include <SFML/Graphics.hpp> #include <vector> // 定义游戏状态、方块等类... class Block; enum class GameState { IDLE, MOVING }; // 键盘控制类 class KeyboardControl { private: sf::RenderWindow window; sf::Event event; std::vector<Block*> blocks; GameState gameState; public: KeyboardControl() { window.create(sf::VideoMode(800, 600), "2048"); window.setKeyRepeatEnabled(false); // 关闭默认的键重复 } void update() { while (window.pollEvent(event)) { switch (event.type) { case sf::Event::KeyPressed: handleKeyPress(event.key.code); break; // 其他事件处理... } } } void handleKeyPress(sf::Keyboard::Key key) { switch (gameState) { case GameState::MOVING: move(key); break; // 更多的游戏状态处理... } } // 根据按键移动方块的方法 void move(sf::Keyboard::Key key) { // 检查键盘对应的移动方向... if (key == sf::Keyboard::Left) moveLeft(); // ...类似地添加对Right, Up, Down的判断 } // 实现具体的方块移动逻辑... void moveLeft() { // 使用blocks的索引来更新位置... } }; ``` 在这个例子中,我们创建了一个`KeyboardControl`类,负责监听窗口的事件,特别是键盘按键。当接收到`sf::Event::KeyPressed`事件时,我们会检查按键对应的方向,并执行相应的移动方块操作。 注意,这只是一个基础框架,实际的2048游戏还会包括更多的逻辑,例如合并方块、检查胜利或失败条件、显示得分等等。你需要根据游戏的具体规则来完善这些功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值