前言
高中時班上有一位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;
}