2048小游戏


背景:

程序设计时,想了一个有意思的题目。

本在DOS环境下可以实现,老师要求写成可视化交互界面。

第一次写交互界面,用的是MFC,过程略痛苦,不断百度调试,好在完成了!

只上DOS环境下的代码,MFC实现函数略混乱,只给出实现窗口界面。:)

游戏截图:

MFC版:




#include<iostream>
#include<string.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<fstream>
using namespace std;

int aMark=1;  //标记保证满2048只输出一次恭喜对话框
int bMark=1; //标记数组是否改变了  改变了为1 不改变为0 为0 不生成新的数字
void m1();
void m2();
void m3();
void m4();
int j=1;

class Game
{
private:
	int x,y,score;
	int a[4][4];
public:
	Game();
	void systemset();
	void RanGenerate();
	void Play(char dir);
	void Show();
	bool IsFail();
	void Save();
friend void menu(); //声明友员 在写入文件的时候访问私有成员
friend void Enter_Game();
};


class User
{
public:
	void Enter_Game();
};



Game::Game()//初始化全为0
{
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
		{
			a[i][j]=0;
		}
		score=0;
}

void Game::Save()
{
	ofstream outf("D:\\2048存档.think_ycx");
	if(!outf)
	{
		MessageBox(0,"Cannot open the file\n"," ",0);
		return ;
	}
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
			outf<<a[i][j]<<' '; 

	MessageBox(0,"已保存\n"," ",0);
	outf.close();
}

void Game::Show()//输出数组
{
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
		{
			if(a[i][j]!=0)	cout<<"	"<<a[i][j]<<"	";  //如果是0不输出会混乱!
			else cout<<"		";
			if(j==3) cout<<"\n\n";
		}
	score=0;
	for(i=0;i<4;i++)
		for(int j=0;j<4;j++)
		{
			score+=a[i][j];
		
		}
		cout<<"分数:"<<score<<endl;
		for(i=0;i<4;i++)
			for(int j=0;j<4;j++)
			if(a[i][j]>=2048&&aMark==1) //达到2048弹出窗口提醒
			{
				MessageBox(0, "Congratulations!\n You can achieve more scores!", "Notice:", 0);
				aMark=0;
			}	
}
void Game::systemset()
{
	system("title 2048游戏中"); //窗口显示2048
}


void Game::Play(char dir)//按照一定的方向移动
{
   int b[4][4],aa[4][4];
   if(dir=='W'||dir=='w'||dir=='S'||dir=='s'||dir=='A'||dir=='a'||dir=='D'||dir=='d')
   {
	   	for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
		{
				aa[i][j]=0;
				b[i][j]=a[i][j];
		}
   }
	if(dir=='W'||dir=='w')
	{
		for(int j=0;j<4;j++)
		{
			int k=0;
			for(int i=0;i<4;i++)
			{
				if(a[i][j]!=0)
				{
					aa[k++][j]=a[i][j];
				}
			}

		}
		int	i=0;
	for(;i<4;i++)
		for(int j=0;j<4;j++)
		{
			a[i][j]=aa[i][j];
		}

	}
	else if(dir=='S'||dir=='s')//---------
	{

		for(int j=0;j<4;j++)     //注意逆序 从下往上赋值
		{
			int k=3;
			for(int i=3;i>=0;i--)
			{
				if(a[i][j]!=0)
				{
					aa[k--][j]=a[i][j];
				}
			}

		}
		int	i=0;
	for(;i<4;i++)
		for(int j=0;j<4;j++)
		{
			a[i][j]=aa[i][j];
		}

	}
	else if(dir=='A'||dir=='a') //移动每一行
	{
		
		
	int	i=0;
		for(;i<4;i++)
		{
			int k=0;
			for(int j=0;j<4;j++) 
			{
				if(a[i][j]!=0)
				{
					aa[i][k++]=a[i][j];
				}
			}

		}
			i=0;
	for(;i<4;i++)
		for(int j=0;j<4;j++)
		{
			a[i][j]=aa[i][j];
		}

	
	}
	else if(dir=='D'||dir=='d') //-------
	{
		
       int i=0;
		for(;i<4;i++)
		{
			int k=3;
			for(int j=3;j>=0;j--) 
			{
				if(a[i][j]!=0)
				{
					aa[i][k--]=a[i][j];
				}
			}

		}
			i=0;
	for(;i<4;i++)
		for(int j=0;j<4;j++)
		{
			a[i][j]=aa[i][j];
		}

	}

//按照规定方向混合         

	if(dir=='W'||dir=='w')
	{
		for(int j=0;j<4;j++)//对每一列合并
		{
			for(int i=0;i<3;i++)
			{
				if(a[i][j]==a[i+1][j]   &&a[i][j]!=0)//相等并且不为0
				{	
					a[i][j]=2*a[i][j];
					a[i+1][j]=0;                                     //考虑 2 2 0 0
					if(i==0&&a[i+2][j]==a[i+3][j]   &&a[i+2][j]!=0)  //考虑一列的特殊情况 例如 2 2 4 4   变成 4 8 0 0
					{
						a[i+1][j]=2*a[i+2][j];
						a[i+2][j]=0;
						a[i+3][j]=0;
					}
					else if(i==0 && a[i+2][j]!=0)  //考虑 2 2 4 ' '  或者 2 2 4 8
					{
						a[i+1][j]=a[i+2][j];
						a[i+2][j]=a[i+3][j];
						a[i+3][j]=0;
					}
					else if(i==1   &&a[i+2][j]!=0) //  2 4 4 8
					{
						a[i+1][j]=a[i+2][j];
						a[i+2][j]=0;
					}

				}

			
			}
		}
	}
	else if(dir=='S'||dir=='s')
	{
		for(int j=0;j<4;j++)//对每一列合并
		{
			for(int i=3;i>0;i--)
			{
				if(a[i][j]==a[i-1][j]   &&a[i][j]!=0)//相等并且不为0
				{	
					a[i][j]=2*a[i][j];
					a[i-1][j]=0;                                     //考虑 2 2 0 0
					if(i==3&&a[i-2][j]==a[i-3][j]   &&a[i-2][j]!=0)  //考虑一列的特殊情况 例如 2 2 2 2  变成 0 0 4 4
					{
						a[i-1][j]=2*a[i-2][j];
						a[i-2][j]=0;
						a[i-3][j]=0;
					}
					else if(i==3&&a[i-2][j]!=0)  //考虑 0 4 2 2   或者 8 4 2 2 
					{
						a[i-1][j]=a[i-2][j];
						a[i-2][j]=a[i-3][j];
						a[i-3][j]=0;
					}
					else if(i==2   &&a[i][j]!=0) //考虑 0 4 4 2  或者 8 4 4 2
					{
						a[i-1][j]=a[i-2][j];
						a[i-2][j]=0;
					}
		
					
				}
			
			}
		}
	}
	else if(dir=='A'||dir=='a')
	{
		for(int i=0;i<4;i++)//对每一行合并
		{
			for(int j=0;j<3;j++)
			{
				if(a[i][j]==a[i][j+1]   &&a[i][j]!=0)//相等并且不为0
				{	
					a[i][j]=2*a[i][j];
					a[i][j+1]=0;                                     //考虑 2 2 0 0
					if(j==0&&a[i][j+2]==a[i][j+3]   &&a[i][j+2]!=0)  //考虑一列的特殊情况 例如 2 2 4 4   变成 4 8 0 0
					{
						a[i][j+1]=2*a[i][j+2];
						a[i][j+2]=0;
						a[i][j+3]=0;
					}
					else if(j==0&&a[i][j+2]!=0)  //考虑 2 2 4 ' '  或者 2 2 4 8
					{
						a[i][j+1]=a[i][j+2];
						a[i][j+2]=a[i][j+3];
						a[i][j+3]=0;
					}
					else if(j==1   &&a[i][j]!=0) //考虑 2 4 4 ' '  或者 2 4 4 8
					{
						a[i][j+1]=a[i][j+2];
						a[i][j+2]=0;
					}
					
				}
			
			}
		}
	}
	else if(dir=='D'||dir=='d')
	{
		for(int i=0;i<4;i++)//对每一行合并
		{
			for(int j=3;j>0;j--)
			{
				if(a[i][j]==a[i][j-1]   &&a[i][j]!=0)//相等并且不为0
				{	
					a[i][j]=2*a[i][j];
					a[i][j-1]=0;                                     //考虑 2 2 0 0
					if(j==3&&a[i][j-2]==a[i][j-3]   &&a[i][j-2]!=0)  //考虑一列的特殊情况 例如 2 2 2 2  变成 0 0 4 4
					{
						a[i][j-1]=2*a[i][j-2];
						a[i][j-2]=0;
						a[i][j-3]=0;
					}
					else if(j==3&&a[i][j-2]!=0)  //考虑 0 4 2 2   或者 8 4 2 2 
					{
						a[i][j-1]=a[i][j-2];
						a[i][j-2]=a[i][j-3];
						a[i][j-3]=0;
					}
					else if(j==2  &&a[i][j]!=0) //考虑 0 4 4 2  或者 8 4 4 2
					{
						a[i][j-1]=a[i][j-2];
						a[i][j-2]=0;
					}
					
				}
			
			}
		}
	}
	if(dir=='W'||dir=='w'||dir=='a'||dir=='A'||dir=='d'||dir=='D'||dir=='s'||dir=='S')
	{
		bMark=0;
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
			
			if(a[i][j]!=b[i][j]) bMark=1;
	}
}

void Game::RanGenerate()//随机生成一个数
{	int value=1;					//不满并且移动了才生成一个新数字  如果两个数组完全一样 则不生成新数字-------------------------------------------------


	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
		{
			if(a[i][j]==0) value=0;
		}
			
		if(bMark==0)  return ;
		


		if(value==1)  //如果满了直接退出,不生成新数字。
		{
			return; 
		}

	srand(time(0));//保证每次的x y temp 是随机的
	do{
	x=rand()%4;
	y=rand()%4;
	}while(a[x][y]!=0);
	int temp;//生成的新数是2 或者4
	temp=rand()%3;
	switch(temp)
	{
	case 0: a[x][y]=2; break;
	case 1: a[x][y]=2; break;
	case 2: a[x][y]=4;
	}	

}

bool Game::IsFail()//判断是否输了 满+不能合并 
{
	int value=1; //value 1表示数组满 0表示 存在空的地方
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
		{
			if(a[i][j]==0) value=0;
		}
		if(value==0) return false; //false表示没有输
		else //判断满了之后能不能混合
		{
			for(int i=0;i<3;i++) //相邻两行的四个元素进行比较,如果相同,则没有输,返回false
				for(int j=0;j<4;j++)
				{
					if(a[i][j]==a[i+1][j]) return false; 
				}
			for(int j=0;j<3;j++) //相邻两列的四个元素进行比较,如果相同,则没有输,返回false
				for(int i=0;i<4;i++)
				{
					if(a[i][j]==a[i][j+1]) return false;
				}
		}
		return true;          //true 表示游戏输了
}
void User::Enter_Game()
{
	Game G;
	char dir;// W  S A  D
		G.systemset();//初始化系统设置
		G.RanGenerate();
		G.RanGenerate();
		G.Show();     //默认是输出两个数字
	while(1)
	{
	dir=getch();
	if(G.IsFail()==true)//判断能不能继续
	{	
			MessageBox(0, "Game Over", "",0);    //弹出对话框之后的输入会暂时放在内存里。
			j=1;
			m1();break;
	}
	G.Play(dir); //此函数应该在 RanGenerate()之前
		switch(dir)                    /*对输入进行判断*/
		{
			case 87: 
			case 119: 
			case 83:
			case 115:
			case 97:
			case 65:        
			case 100:
			case 68:        G.RanGenerate(); break;
			case 27:		system("CLS");m1();  break; //ESC
			case 66:
			case 98:	 G.Save();    break;                         //B b
			case 82:
			case 114:system("cls");  User R;   R.Enter_Game(); break;
			default:break;
		}
		system("cls");//清屏
		G.Show();		
	}
}


void menu()
{
	char a;    // 获取  W S ENTER
	a=getch();
	switch(a)
	{
	    case 87:                                  // w W
		case 119:    --j;  	if(j<=0) j=4; break; 
		case 83:								  // s S
		case 115:    ++j;  	if(j>4)	j=1; break;
	}
	system("cls");

	if(a==13&&j==1)
	{
		User U;
		U.Enter_Game();
	}

	
	if(a==13&&j==2)
	{
		system("cls");
		ifstream inf("D:\\2048存档.think_ycx");
		if(!inf)
		{
			MessageBox(0,"无存档\n"," ",0);
			return ;
		}
		Game G;
		for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
				 inf>>G.a[i][j];
			G.Show();

	while(1)
	{
		char dir;
	dir=getch();
					if(G.IsFail()==true)//判断能不能继续
					{	
							MessageBox(0, "Game Over", "",0);    //弹出对话框之后的输入会暂时放在内存里。
							system("cls");
							j=1;
							m1();
				
									//一些函数 分数 保存 载入排行榜
						break;
					}
							G.Play(dir); //此函数应该在 RanGenerate()之前

		
		switch(dir)                    /*对输入进行判断*/
		{
			case 87: 
			case 119: 
			case 83:
			case 115:
			case 97:
			case 65:        
			case 100:
			case 68:        G.RanGenerate(); break;
			case 27:		system("CLS");m1();  break; //ESC
			case 66:
			case 98:	 G.Save();    break;                         //B b
			case 82:
			case 114:system("cls");  User R;   R.Enter_Game(); break;
			default:break;
		}
		system("cls");//清屏
		G.Show();			
	}			
	}

	if(a==13&&j==3)
	{
		cout<<"\n\n";
		cout<<"\t		  Help  			\n\n";
		cout<<"\t W S A D		控制空格上下左右移动\n";
		cout<<"\t Esc			返回菜单\n";
		cout<<"\t R			重新开始\n";
		cout<<"\t B			保存\n\n\n";
		cout<<"按任意键键返回"<<endl;
		char choice;                //为什么是任意键呢?因为如果是ACSII==27 如果不等 直接进入下次循环。所以直接返回即可
		choice=getch();
		if(choice) system("cls");
	}



	if(a==13&&j==4)
	{
		system("cls");
		MessageBox(0,"   再见"," ",0);
		exit(1);
	}

	switch(j)
	{
		case 1: m1(); break;
		case 2: m2(); break;
		case 3: m3(); break;
		case 4: m4(); break;
	}
}

void m1()
{
	cout<<"\n\n\n\n";
	cout<<"                W或S选择,回车确定\n";
	cout<<"   **              —> 新游戏             **\n";
	cout<<"   **                  继续游戏           **\n";
	cout<<"   **                  帮助               **\n";
	cout<<"   **                  退出               **\n";
	menu();
}
void m2()
{
	cout<<"\n\n\n\n";
	cout<<"                W或S选择,回车确定\n";
	cout<<"   **                  新游戏             **\n";
	cout<<"   **              —> 继续游戏           **\n";
	cout<<"   **                  帮助               **\n";
	cout<<"   **                  退出               **\n";
	menu();
}
void m3()
{
	cout<<"\n\n\n\n";
	cout<<"                W或S选择,回车确定\n";
	cout<<"   **                  新游戏             **\n";
	cout<<"   **                  继续游戏           **\n";
	cout<<"   **              —> 帮助               **\n";
	cout<<"   **                  退出               **\n";
	menu();
}
void m4()
{
	cout<<"\n\n\n\n";
	cout<<"                W或S选择,回车确定\n";
	cout<<"   **                  新游戏             **\n";
	cout<<"   **                  继续游戏           **\n";
	cout<<"   **                  帮助               **\n";
	cout<<"   **              —> 退出               **\n";
	menu();
}


#include"menu.h"
#include<iostream>
#include<conio.h>
#include<windows.h>
using namespace std;
void main()
{ 
	m1();
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值