背景:
程序设计时,想了一个有意思的题目。
本在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();
}