首页 > 技术文章 > 基于C++控制台的2048简单实现

liujw2114 2017-02-01 09:18 原文

本文为大大维原创,最早于博客园发表,转载请注明出处!!!

 

前几天由于忙着过年串门,游戏机的计划搁置了几天。这两天终于空出了一块时间,抽空写了2048。

由于笔者前面自制了一个类似2048的游戏,所以写起来也算是轻车熟路,花了两个晚上也就差不多了。

废话少说,先将代码copy一份过来!

后续这几天,笔者想先写一个拼图小游戏,然后想办法将这几个游戏中共同存在的全屏刷新闪屏的问题给解决了。

另外,整个程序代码均为笔者原创,引用或转载请注明出处!

  1 /**--------------------------------------------------------------**/
  2 /**名称:大大维的2048v1                            日期:2017/2/1**/
  3 /**描述:简单地实现了2048的基本功能                            **/
  4 /**存在的问题:由于使用了全局刷新,游戏运行中会出现闪屏现象;
  5 不能够存储玩家的游戏记录;由于不是图形化界面,用户界面较丑;
  6 不能改变游戏的地图大小                                          **/
  7 /**笔者会在后续版本逐步完善这些问题!!!                         **/
  8 /**-------------------------------------------------------------**/
  9 /**申明: 1.本程序由大大维独自编写,转载、引用请注明出处
 10          2.本程序注释掉的部分,笔者认为理论上可以替代后续的代码,
 11          但存在错误。笔者未发现错误原因,如有高手发现,请联系笔者
 12          3.程序中若存在BUG请联系笔者
 13          4.笔者联系方式   1329423134@qq.com                     **/
 14 /**-------------------------------------------------------------**/
 15 #include<iostream>
 16 #include<string>
 17 #include<vector>
 18 #include<ctime>
 19 #include<cstdlib>
 20 #include<conio.h>
 21 using namespace std;
 22 constexpr unsigned HIGH=4;
 23 constexpr unsigned LENG=4;
 24 ///当前地图状态:READY,即(),可以进行moveAndAddData()操作;WAIT,即[],可以进行chooseMapSpace()操作
 25 enum state {READY,WAIT};
 26 ///当前操作块的移动方向:UP,上;DOWN,下;LEFT,左;RIGHT,右;DEFAULT,其他
 27 enum dir {UP,DOWN,LEFT,RIGHT,DEFAULT};
 28 class Map2048
 29 {
 30 public:
 31     Map2048();///构造函数,初始化数据
 32     void moveAndAddData();///移动和相加选中块的数据
 33     ///地图压缩
 34     void mapSortToUp();
 35     void mapSortToDown();
 36     void mapSortToLeft();
 37     void mapSortToRight();
 38     void dataCreate(unsigned persentOf2);///生成新data
 39     bool isLive();///是否存活判断
 40     void printMap();///地图打印
 41     dir setDir();///输入操作块的移动方向
 42     string dataToPrintData(int n);///data到printData的转换函数
 43     unsigned getScore();
 44 private:
 45     unsigned data[HIGH][LENG];///设要显示数据为x,data=log2(x),空白时,data=0
 46     string printData[HIGH][LENG];///存储规范化的输出数据
 47     unsigned score;
 48 };
 49 
 50 Map2048::Map2048()
 51 {
 52     for(int i=0; i<HIGH; i++)
 53         for(int j=0; j<LENG; j++)
 54         {
 55             data[i][j]=0;
 56         }
 57     for(int i=0; i<HIGH; i++)
 58         for(int j=0; j<LENG; j++)
 59             printData[i][j]=dataToPrintData(data[i][j]);
 60     bool initFlag=true;
 61     while(initFlag)
 62     {
 63         srand((unsigned)time(NULL));
 64         int x1=rand()%HIGH,y1=rand()%LENG,x2=rand()%HIGH,y2=rand()%LENG;
 65         if(x1!=x2&&y1!=y2)
 66         {
 67             initFlag=false;
 68             data[x1][y1]=data[x2][y2]=2;
 69             printData[x1][y1]=dataToPrintData(data[x1][y1]);
 70             printData[x2][y2]=dataToPrintData(data[x2][y2]);
 71         }
 72     }
 73     score=0;
 74 }
 75 
 76 void Map2048::moveAndAddData()
 77 {
 78     dir DIR=setDir();
 79     switch(DIR)
 80     {
 81     case UP:
 82     {
 83         mapSortToUp();
 84         for(int n=0; n<LENG; n++)
 85             for(int m=1; m<HIGH; m++)
 86                 if(data[m][n]==data[m-1][n])
 87                 {
 88                     data[m-1][n]*=2;
 89                     data[m][n]=0;
 90                     printData[m-1][n]=dataToPrintData(data[m-1][n]);
 91                     printData[m][n]=dataToPrintData(data[m][n]);
 92                     score+=data[m-1][n];
 93                 }
 94         mapSortToUp();
 95         break;
 96     }
 97     case DOWN:
 98     {
 99         mapSortToDown();
100         for(int n=0; n<LENG; n++)
101             for(int m=HIGH-2; m>=0; m--)
102                 if(data[m][n]==data[m+1][n])
103                 {
104                     data[m+1][n]*=2;
105                     data[m][n]=0;
106                     printData[m+1][n]=dataToPrintData(data[m+1][n]);
107                     printData[m][n]=dataToPrintData(data[m][n]);
108                     score+=data[m+1][n];
109                 }
110         mapSortToDown();
111         break;
112     }
113     case LEFT:
114     {
115         mapSortToLeft();
116         for(int m=0; m<HIGH; m++)
117             for(int n=1; n<LENG; n++)
118                 if(data[m][n]==data[m][n-1])
119                 {
120                     data[m][n-1]*=2;
121                     data[m][n]=0;
122                     printData[m][n-1]=dataToPrintData(data[m][n-1]);
123                     printData[m][n]=dataToPrintData(data[m][n]);
124                     score+=data[m][n-1];
125                 }
126         mapSortToLeft();
127         break;
128     }
129     case RIGHT:
130     {
131         mapSortToRight();
132         for(int m=0; m<HIGH; m++)
133             for(int n=LENG-2; n>=0; n--)
134                 if(data[m][n]==data[m][n+1])
135                 {
136                     data[m][n+1]*=2;
137                     data[m][n]=0;
138                     printData[m][n+1]=dataToPrintData(data[m][n+1]);
139                     printData[m][n]=dataToPrintData(data[m][n]);
140                     score+=data[m][n+1];
141                 }
142         mapSortToRight();
143         break;
144     }
145     case DEFAULT:
146         break;
147     }
148 }
149 
150 void Map2048::mapSortToUp()///地图向上压缩
151 {
152     for(int n=0; n<LENG; n++)
153         for(int m=0; m<HIGH; m++)
154             if(data[m][n]==0)
155                 for(int k=m; k<HIGH; k++)
156                     if(data[k][n]!=0)
157                     {
158                         data[m][n]=data[k][n];
159                         data[k][n]=0;
160                         printData[m][n]=dataToPrintData(data[m][n]);
161                         printData[k][n]=dataToPrintData(data[k][n]);
162                         break;
163                     }
164 }
165 
166 void Map2048::mapSortToDown()///地图向下压缩
167 {
168     for(int n=LENG-1; n>=0; n--)
169         for(int m=HIGH-1; m>=0; m--)
170             if(data[m][n]==0)
171                 for(int k=m; k>=0; k--)
172                     if(data[k][n]!=0)
173                     {
174                         data[m][n]=data[k][n];
175                         data[k][n]=0;
176                         printData[m][n]=dataToPrintData(data[m][n]);
177                         printData[k][n]=dataToPrintData(data[k][n]);
178                         break;
179                     }
180 }
181 
182 void Map2048::mapSortToLeft()///地图向左压缩
183 {
184     for(int m=0; m<HIGH; m++)
185         for(int n=0; n<LENG; n++)
186             if(data[m][n]==0)
187                 for(int k=n; k<LENG; k++)
188                     if(data[m][k]!=0)
189                     {
190                         data[m][n]=data[m][k];
191                         data[m][k]=0;
192                         printData[m][n]=dataToPrintData(data[m][n]);
193                         printData[m][k]=dataToPrintData(data[m][k]);
194                         break;
195                     }
196 }
197 
198 void Map2048::mapSortToRight()///地图向右压缩
199 {
200     for(int m=HIGH-1; m>=0; m--)
201         for(int n=LENG-1; n>=0; n--)
202             if(data[m][n]==0)
203                 for(int k=n; k>=0; k--)
204                     if(data[m][k]!=0)
205                     {
206                         data[m][n]=data[m][k];
207                         data[m][k]=0;
208                         printData[m][n]=dataToPrintData(data[m][n]);
209                         printData[m][k]=dataToPrintData(data[m][k]);
210                         break;
211                     }
212 }
213 
214 void Map2048::dataCreate(unsigned persentOf2)
215 {
216     vector<int> dataVecX;///加入一个矢量,记录空位置的x坐标
217     vector<int> dataVecY;///加入一个矢量,记录空位置的y坐标
218     for(int i=0; i<HIGH; i++)
219         for(int j=0; j<LENG; j++)
220         {
221             if(data[i][j]==0)
222             {
223                 dataVecX.push_back(i);
224                 dataVecY.push_back(j);
225             }
226         }
227     if(!dataVecX.empty())
228     {
229         srand((unsigned)time(NULL));
230         auto k=rand()%dataVecX.size();///在空位中随机选择一个位置
231         if(rand()%100<persentOf2)///根据2,4生成的比例随机生成新数据
232             data[dataVecX[k]][dataVecY[k]]=2;
233         else
234             data[dataVecX[k]][dataVecY[k]]=4;
235         printData[dataVecX[k]][dataVecY[k]]=dataToPrintData(data[dataVecX[k]][dataVecY[k]]);
236     }
237 }
238 
239 bool Map2048::isLive()
240 {
241     bool liveFlag=false;
242     for(int m=0; m<HIGH; m++) ///确保没有空位置
243         for(int n=0; n<LENG; n++)
244             if(data[m][n]==0)
245             {
246                 liveFlag=true;
247                 return liveFlag;
248             }
249 //    ///以下代码基于如下数学关系:反复使用向右,向下查询
250 //    ///(最右行只向下,最底行只向右),可以遍历检查一遍元素自身是否与邻居相等
251 //    for(int i=0; i<HIGH; i++)
252 //    {
253 //        for(int j=0; j<LENG; j++)
254 //        {
255 //            if(i!=HIGH-1&&j!=LENG-1)///非最右且非最下节点
256 //            {
257 //                if(data[i][j]==data[i][j+1]||data[i][j]==data[i+1][j])///向右,向下比较
258 //                {
259 //                    liveFlag=true;
260 //                    return liveFlag;
261 //                }
262 //            }
263 //            else if(i==HIGH-1&&j!=LENG-1)///非最右但是最下节点
264 //            {
265 //                if(data[i][j]=data[i][j+1])///向右比较
266 //                {
267 //                    liveFlag=true;
268 //                    return liveFlag;
269 //                }
270 //            }
271 //            else if(i!=HIGH-1&&j==LENG-1)///非最下但是最右节点
272 //            {
273 //                if(data[i][j]=data[i+1][j])///向下比较
274 //                {
275 //                    liveFlag=true;
276 //                    return liveFlag;
277 //                }
278 //            }
279 //            else///末尾节点,即最下且最右节点,无须比较,直接返回标志
280 //                return liveFlag;
281 //        }
282 //    }
283     for(int m=0; m<HIGH; m++) ///确保没有空位置
284         for(int n=0; n<LENG; n++)
285         {
286             if((m==0)&&(n==0))
287             {
288                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m][n+1])
289                 {
290                     liveFlag=true;
291                     return liveFlag;
292                 }
293             }
294             else if((m==HIGH-1)&&(n==LENG-1))
295             {
296                 if(data[m][n]==data[m-1][n]||data[m][n]==data[m][n-1])
297                 {
298                     liveFlag=true;
299                     return liveFlag;
300                 }
301             }
302             else if((m==0)&&(n==LENG-1))
303             {
304                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m][n-1])
305                 {
306                     liveFlag=true;
307                     return liveFlag;
308                 }
309             }
310             else if((m==HIGH-1)&&(n==0))
311             {
312                 if(data[m][n]==data[m-1][n]||data[m][n]==data[m][n+1])
313                 {
314                     liveFlag=true;
315                     return liveFlag;
316                 }
317             }
318             else if((m==0)&&(n!=0)&&(n!=LENG-1))
319             {
320                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m][n-1]||data[m][n]==data[m][n+1])
321                 {
322                     liveFlag=true;
323                     return liveFlag;
324                 }
325             }
326             else if((m=HIGH-1)&&(n!=0)&&(n!=LENG-1))
327             {
328                 if(data[m][n]==data[m-1][n]||data[m][n]==data[m][n-1]||data[m][n]==data[m][n+1])
329                 {
330                     liveFlag=true;
331                     return liveFlag;
332                 }
333             }
334             else if((n==0)&&(m!=0)&&(m!=HIGH-1))
335             {
336                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m-1][n]||data[m][n]==data[m][n+1])
337                 {
338                     liveFlag=true;
339                     return liveFlag;
340                 }
341             }
342             else if((n==LENG-1)&&(m!=0)&&(m!=HIGH-1))
343             {
344                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m-1][n]||data[m][n]==data[m][n-1])
345                 {
346                     liveFlag=true;
347                     return liveFlag;
348                 }
349             }
350             else
351             {
352                 if(data[m][n]==data[m+1][n]||data[m][n]==data[m-1][n]||data[m][n]==data[m][n-1]||data[m][n]==data[m][n+1])
353                 {
354                     liveFlag=true;
355                     return liveFlag;
356                 }
357             }
358         }
359 }
360 
361 void Map2048::printMap()
362 {
363     cout<<"               2    0    4    8"<<endl;
364     cout<<"---------------------------------------------"<<endl;
365     for(int i=0; i<HIGH; i++)
366     {
367         for(int j=0; j<LENG; j++)
368         {
369             if(data[i][j]!=0)
370                 cout<<"|  "<<printData[i][j]<<"  ";
371             else
372                 cout<<"|  "<<"      "<<"  ";
373         }
374         cout<<"|"<<endl;
375         cout<<"---------------------------------------------"<<endl;
376     }
377     cout<<"SCORE= "<<score;
378 }
379 
380 dir Map2048::setDir()
381 {
382     char keydown=getch();///读取按键
383     switch(keydown)
384     {
385     case 'w':
386         return UP;
387         break;
388     case 'W':
389         return UP;
390         break;
391     case 's':
392         return DOWN;
393         break;
394     case 'S':
395         return DOWN;
396         break;
397     case 'a':
398         return LEFT;
399         break;
400     case 'A':
401         return LEFT;
402         break;
403     case 'd':
404         return RIGHT;
405         break;
406     case 'D':
407         return RIGHT;
408         break;
409     default:
410         return DEFAULT;
411         break;
412     }
413 }
414 
415 string Map2048::dataToPrintData(int m)
416 {
417 
418     int count=0;
419     ///str的初始化基于如下数学关系:4*4的地图下,2048游戏能合成数,理论上最大值131072(2^17),即data最大为17
420     string str {m/100000+48,(m/10000)%10+48,(m/1000)%10+48,(m/100)%10+48,(m/10)%10+48,m%10+48};
421     ///对冗余0的处理
422     for(int i=0; i<6; i++)
423     {
424         if(str[i]=='0')
425         {
426             count++;
427             str[i]=' ';
428         }
429         else
430             break;
431     }
432     switch(count)///格式调整
433     {
434     case 2:///不加break会在执行完第一条语句后自动执行break
435     {
436         str[1]=str[2];
437         str[2]=str[3];
438         str[3]=str[4];
439         str[4]=str[5];
440         str[5]=' ';
441         break;
442     }
443     case 3:
444     {
445         str[2]=str[3];
446         str[3]=str[4];
447         str[4]=str[5];
448         str[5]=' ';
449         break;
450     }
451     case 4:
452     {
453         str[2]=str[4];
454         str[3]=str[5];
455         str[4]=' ';
456         str[5]=' ';
457         break;
458     }
459     case 5:
460     {
461         str[3]=str[5];
462         str[5]=' ';
463         break;
464     }
465     }
466     return str;
467 }
468 
469 unsigned Map2048::getScore()
470 {
471     return score;
472 }
473 
474 int main()
475 {
476     Map2048 map;
477     bool gameOverFlag=false;
478     map.printMap();
479     while(!gameOverFlag)
480     {
481         while(kbhit())
482         {
483             system("cls");
484             map.moveAndAddData();
485             map.dataCreate(50);///以50%为2,50%为4的规则生成新数据
486             map.printMap();
487             if(!map.isLive())
488                 gameOverFlag=true;
489         }
490     }
491     cout<<endl<<"GAME OVER"<<endl;
492     cout<<"The Final Score Is: "<<map.getScore()<<endl;
493     getch();
494 }
View Code

老规矩,上几张游戏截图:(在codeblocks下编译)

 

推荐阅读