前言
高中时班上有一位dalao用了大概一周的时间搞出来了控制台版的2048。然后今天上实验课的时候突发想到,我既然现在已经是这个专业的了,然后自认为自己的代码量还算看得过去,这个控制台版的应该不会太难,于是就开始敲。
一天的时间,敲出来了V1.0的版本,如果有BUG的话请留言,我会尽力进行更改,有修改意见也望提出。
大致思路
其实2048的变化过程玩过游戏的应该都是知道的,在这里就不多赘述。
先说一下大概的思路:
一个二维整形数组,两个布尔数组。
整形数组是用来存每一个方块的数字的,方便之后的计算。
第一个布尔数组用来存每一个单元是否有方块,其实这个功能可以用整形数组去实现,但在敲的过程中容易混淆,也不好debug。所以还是用一个布尔数组去存比较方便。
第二个布尔数组是为了防止重复计算。例如现在一行的情况是 | 0 | 4 | 2 | 2|。然后向右移动,从右往左判断时,因为2+2已经运算过,给最右边的那个格子进行标记。表示已经运算过,不能再次运算。
在编码过程中收获最大的可能是知道了怎么实时知道键盘上按下的情况。不过就是一个简单的库函数,只不过以前不知道罢了。
#include<cstdio>
#include<conion.h>
using namespace std;
int main()
{
char ch;
ch=getch();
printf("%c %d\n",ch,ch);
return 0;
}
不知道的什么意思的话,把这个代码拷贝到IDE里run一下,再随便按几个字母就肯定明白了。
而整个2048的动作就是建立在这个函数的基础上。
实现函数
1) 打印矩阵
void print()
{
for(int j=0;j<4;++j)
printf("----");
printf("\n");
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
printf("|");
if(map[i][j]){//有数字就打印,没有就打印空格
if(score<mp[i][j])
score=mp[i][j];//更新最高分
printf("%3d",mp[i][j]);
}else
printf(" ");
}
printf("|\n");
for(int j=0;j<4;++j)
printf("----");
printf("\n");
}
printf("w : up s : down a : left d : right\n");
printf("push 'r' to start a new game\npush 'e' to exit game\n");//动作按钮
}
2) 向上移动
四个方向的移动都大同小异,所以只对向上的部分进行注释
void MoveUp()
{
bool flag;//标记是否有合法合并点
for(int i=1;i<4;++i){//因为是向上,所以第一行不考虑
for(int j=0;j<4;++j){
if(!map[i][j])//没有数字的点不考虑
continue;
flag=false;
int pos=i;
for(int k=i-1;k>=0;--k){
if(!map[k][j]){//可以移动到的空格地址
pos=k;
continue;
}
if((mp[k][j]==mp[i][j])&&(!cal[k][j])){//值相同且没有进行过计算的点
mp[k][j]+=mp[i][j];
cal[k][j]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){//点更新
mp[pos][j]=mp[i][j];
map[i][j]=false;
map[pos][j]=true;
}
}
}
}
3) 向下移动
void MoveDown()
{
bool flag;
for(int i=2;i>=0;--i){
for(int j=0;j<4;++j){
if(!map[i][j])
continue;
flag=false;
int pos=i;
for(int k=i+1;k<4;++k){
if(!map[k][j]){
pos=k;
continue;
}
if((mp[k][j]==mp[i][j])&&(!cal[k][j])){
mp[k][j]+=mp[i][j];
cal[k][j]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[pos][j]=mp[i][j];
map[i][j]=false;
map[pos][j]=true;
}
}
}
}
4) 向右移动
void MoveRight()
{
bool flag;
for(int i=0;i<4;++i){
for(int j=2;j>=0;--j){
if(!map[i][j])
continue;
flag=false;
int pos=j;
for(int k=j+1;k<4;++k){
if(!map[i][k]){
pos=k;
continue;
}
if((mp[i][k]==mp[i][j])&&(!cal[i][k])){
mp[i][k]+=mp[i][j];
cal[i][k]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[i][pos]=mp[i][j];
map[i][j]=false;
map[i][pos]=true;
}
}
}
}
5) 向左移动
void MoveLeft()
{
bool flag;
for(int i=0;i<4;++i){
for(int j=1;j<4;++j){
if(!map[i][j])
continue;
flag=false;
int pos=j;
for(int k=j-1;k>=0;--k){
if(!map[i][k]){
pos=k;
continue;
}
if((mp[i][k]==mp[i][j])&&(!cal[i][k])){
mp[i][k]+=mp[i][j];
cal[i][k]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[i][pos]=mp[i][j];
map[i][j]=false;
map[i][pos]=true;
}
}
}
}
6) 初始化
每次给矩阵中增加两个点,并赋值为2或4
void Init()
{
srand(time(NULL));
int x,y,v,now=0;
for(int i=0;i<4;++i)
for(int j=0;j<4;++j)
if(!map[i][j])
now++;//统计还有多少空格
if(now==0)//没有空格就不需要加点
return;
int cnt=rand()%now,n=0;//随机在第n个空白点
bool flag=false;
for(int i=0;i<4;++i){
flag=false;
for(int j=0;j<4;++j)
if(!map[i][j]){
if(cnt==n){
x=i;
y=j;
flag=true;
break;
}else
n++;
}
if(flag)
break;
}
v=rand()%2;
if(v)//两种情况
v=4;
else
v=2;
mp[x][y]=v;
map[x][y]=true;
}
7) 判断游戏是否结束
bool gameover()
{
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
if(!map[i][j])//任意一点为空,游戏继续
return false;
if(i>0){
if(mp[i-1][j]==mp[i][j])//任意两个相邻的单元值相同,游戏继续
return false;
}
if(j>0)
if(mp[i][j-1]==mp[i][j])
return false;
}
}
return true;
}
8) 游戏开始
void start()
{
system("cls");//刷新屏幕
printf("********************\n");
printf("* game start glhf~ *\n");
printf("********************\n");
int x=5e8;
bool flag=false;
while(x--);//为了让glhf停留一段时间
memset(mp,0,sizeof(mp));
memset(map,false,sizeof(map));
score=0;
char ch;
while(!gameover())
{
memset(cal,false,sizeof(cal));//每次动作前都需要对cal进行初始化
int cnt=0;
system("cls");
Init();
print();
// DeBug();调试用
ch=getch();
switch (ch)
{
case 'w':MoveUp();break;
case 's':MoveDown();break;
case 'a':MoveLeft();break;
case 'd':MoveRight();break;
case 'e':exit(0);
case 'r':return ;
}
if(score>=2048){
flag=true;
break;
}
}
if(flag)
Win();
else
Lose();
return ;
}
全部代码
#include<iostream>
#include<cstdio>
#include<conio.h>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
int mp[4][4],score;
bool map[4][4];
bool cal[4][4];
void DeBug()
{
for(int i=0;i<4;++i){
for(int j=0;j<4;++j)
cout<<map[i][j]<<" ";
cout<<endl;
}
cout<<endl;
for(int i=0;i<4;++i){
for(int j=0;j<4;++j)
cout<<mp[i][j]<<" ";
cout<<endl;
}
}
void print()
{
for(int j=0;j<4;++j)
printf("----");
printf("\n");
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
printf("|");
if(map[i][j]){
if(score<mp[i][j])
score=mp[i][j];
printf("%3d",mp[i][j]);
}else
printf(" ");
}
printf("|\n");
for(int j=0;j<4;++j)
printf("----");
printf("\n");
}
printf("w : up s : down a : left d : right\n");
printf("push 'r' to start a new game\npush 'e' to exit game\n");
}
void MoveUp()
{
bool flag;
for(int i=1;i<4;++i){
for(int j=0;j<4;++j){
if(!map[i][j])
continue;
flag=false;
int pos=i;
for(int k=i-1;k>=0;--k){
if(!map[k][j]){
pos=k;
continue;
}
if((mp[k][j]==mp[i][j])&&(!cal[k][j])){
mp[k][j]+=mp[i][j];
cal[k][j]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[pos][j]=mp[i][j];
map[i][j]=false;
map[pos][j]=true;
}
}
}
}
void MoveDown()
{
bool flag;
for(int i=2;i>=0;--i){
for(int j=0;j<4;++j){
if(!map[i][j])
continue;
flag=false;
int pos=i;
for(int k=i+1;k<4;++k){
if(!map[k][j]){
pos=k;
continue;
}
if((mp[k][j]==mp[i][j])&&(!cal[k][j])){
mp[k][j]+=mp[i][j];
cal[k][j]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[pos][j]=mp[i][j];
map[i][j]=false;
map[pos][j]=true;
}
}
}
}
void MoveRight()
{
bool flag;
for(int i=0;i<4;++i){
for(int j=2;j>=0;--j){
if(!map[i][j])
continue;
flag=false;
int pos=j;
for(int k=j+1;k<4;++k){
if(!map[i][k]){
pos=k;
continue;
}
if((mp[i][k]==mp[i][j])&&(!cal[i][k])){
mp[i][k]+=mp[i][j];
cal[i][k]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[i][pos]=mp[i][j];
map[i][j]=false;
map[i][pos]=true;
}
}
}
}
void MoveLeft()
{
bool flag;
for(int i=0;i<4;++i){
for(int j=1;j<4;++j){
if(!map[i][j])
continue;
flag=false;
int pos=j;
for(int k=j-1;k>=0;--k){
if(!map[i][k]){
pos=k;
continue;
}
if((mp[i][k]==mp[i][j])&&(!cal[i][k])){
mp[i][k]+=mp[i][j];
cal[i][k]=true;
flag=true;
map[i][j]=false;
}
else
break;
}
if(!flag){
mp[i][pos]=mp[i][j];
map[i][j]=false;
map[i][pos]=true;
}
}
}
}
void Init()
{
srand(time(NULL));
int x,y,v,now=0;
for(int i=0;i<4;++i)
for(int j=0;j<4;++j)
if(!map[i][j])
now++;
if(now==0)
return;
int cnt=rand()%now,n=0;
bool flag=false;
for(int i=0;i<4;++i){
flag=false;
for(int j=0;j<4;++j)
if(!map[i][j]){
if(cnt==n){
x=i;
y=j;
flag=true;
break;
}else
n++;
}
if(flag)
break;
}
v=rand()%2;
if(v)
v=4;
else
v=2;
mp[x][y]=v;
map[x][y]=true;
}
bool gameover()
{
for(int i=0;i<4;++i){
for(int j=0;j<4;++j){
if(!map[i][j])
return false;
if(i>0){
if(mp[i-1][j]==mp[i][j])
return false;
}
if(j>0)
if(mp[i][j-1]==mp[i][j])
return false;
}
}
return true;
}
void Lose()
{
char ch;
system("cls");
printf("*******************\n");
printf("**** GAME OVER ****\n");
printf("**** SCORE:%3d ****\n",score);
printf("*******************\n\n");
printf("Push any button to continue\n");
ch=getch();
return ;
}
void Win()
{
char ch;
system("cls");
printf("*******************\n");
printf("**** YOU WIN! ****\n");
printf("*******************\n\n");
printf("Push any button to continue\n");
ch=getch();
return ;
}
void start()
{
system("cls");
printf("********************\n");
printf("* game start glhf~ *\n");
printf("********************\n");
int x=5e8;
bool flag=false;
while(x--);
memset(mp,0,sizeof(mp));
memset(map,false,sizeof(map));
score=0;
char ch;
while(!gameover())
{
memset(cal,false,sizeof(cal));
int cnt=0;
system("cls");
Init();
print();
// DeBug();
ch=getch();
switch (ch)
{
case 'w':MoveUp();break;
case 's':MoveDown();break;
case 'a':MoveLeft();break;
case 'd':MoveRight();break;
case 'e':exit(0);
case 'r':return ;
}
if(score>=2048){
flag=true;
break;
}
}
if(flag)
Win();
else
Lose();
return ;
}
int main()
{
char ch;
while(1)
{
system("cls");
printf("push ENTER to start game\nESC to exit\n");
ch=getch();
if(ch==13)
start();
else if(ch==27)
break;
}
return 0;
}