本文为大大维原创,最早于博客园发表,转载请注明出处!!!
前几天由于忙着过年串门,游戏机的计划搁置了几天。这两天终于空出了一块时间,抽空写了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 }
老规矩,上几张游戏截图:(在codeblocks下编译)