基于C++控制台的一个的类似2048的小游戏
本文为大大维原创,最早于博客园发表,转载请注明出处!!!
承接上篇,这几日,笔者本来打算写一个2048的,但写着写着,突然有个想法,能不能搞一个将2048和消消乐结合起来的游戏,于是,笔者便写出了如下这个小游戏。
值得一提的是,整个游戏完全由笔者独自写成,并没有参考任何网上的代码,这跟上次写贪吃蛇前学了老半天网上已有代码就显得独立了很多。看来贪食蛇的书写还是让笔者受益匪浅
定义的游戏规则如下:
1.采用类似2048的游戏规则合成数字
2.加入消消乐的点选作用(类似于在PC端模拟了一下触摸屏)
3.加入地图压缩规则
4.由于游戏像2048,就叫他NEW2048吧
虽然笔者将游戏按照所想做了出来,但笔者玩了一下,可玩性并不高。甚至十分枯燥!!!
尽管如此,这个游戏还是笔者完全独立书写的第一个游戏,意义还是蛮大的,因此笔者还是在此记录一笔。日后再翻出来改改,说不定能更好玩些。
大家可以试试这个游戏,并提提意见,可能有些bug,也请指正。
以后还是接着计划写剩余的游戏,加油。
1 #include<iostream> 2 #include<string> 3 #include<cmath> 4 #include<ctime> 5 #include<cstdlib> 6 #include<conio.h> 7 using namespace std; 8 constexpr unsigned HIGH=4; 9 constexpr unsigned LENG=4; 10 ///当前地图状态:READY,即(),可以进行moveAndAddData()操作;WAIT,即[],可以进行chooseMapSpace()操作 11 enum state {READY,WAIT}; 12 ///当前操作块的移动方向及操作:UP,上;DOWN,下;LEFT,左;RIGHT,右;CHANGE,改变状态;DEFAULT,其他 13 enum dir {UP,DOWN,LEFT,RIGHT,CHANGE,DEFAULT}; 14 class MapNew2048 15 { 16 public: 17 MapNew2048();///构造函数,初始化数据 18 void printMap();///地图打印 19 void chooseMapSpace();///操作块移动,选择想要处理的地图块 20 void moveAndAddData();///移动和相加选中块的数据 21 ///压缩地图,将有意义的数值向左(上)角靠拢 22 void mapSortToUp(); 23 void mapSortToLeft(); 24 ///当一行(一列)完全为空时,随机生成一个数加入地图(这个数不能大于当前所合成的最大数的一半) 25 void dataCreate(); 26 void stateChange();///状态切换函数 27 bool isLive();///是否存活判断 28 state getState();///获取当前地图状态 29 dir setDir();///输入操作块的移动方向 30 unsigned getMaxData(); 31 string dataToPrintData(int n);///data到printData的转换函数 32 private: 33 unsigned data[HIGH][LENG];///设要显示数据为x,data=log2(x),空白时,data=0 34 string printData[HIGH][LENG];///存储规范化的输出数据 35 int nowX;///记录当前操作块的位置 36 int nowY; 37 state sta;///记录当前地图状态,确定执行chooseMapSpace()还是moveAndAddData() 38 bool flag;///记录上次moveAndAddData()操作是否成功 39 }; 40 41 MapNew2048::MapNew2048() 42 { 43 for(int i=0; i<HIGH; i++) 44 for(int j=0; j<LENG; j++) 45 { 46 data[i][j]=1; 47 srand((unsigned)time(NULL)+(2*i+3*j));///确保每一次,地图的每一格生成的data都是随机的 48 unsigned p=rand()%5; 49 if(p!=0) 50 data[i][j]=p; 51 } 52 for(int i=0; i<HIGH; i++) 53 for(int j=0; j<LENG; j++) 54 printData[i][j]=dataToPrintData(data[i][j]); 55 nowX=nowY=0; 56 printData[nowX][nowY][0]='['; 57 printData[nowX][nowY][7]=']'; 58 sta=WAIT; 59 } 60 61 state MapNew2048::getState() 62 { 63 return sta; 64 } 65 66 dir MapNew2048::setDir() 67 { 68 char keydown=getch();///读取按键 69 switch(keydown) 70 { 71 case 'w': 72 return UP; 73 break; 74 case 'W': 75 return UP; 76 break; 77 case 's': 78 return DOWN; 79 break; 80 case 'S': 81 return DOWN; 82 break; 83 case 'a': 84 return LEFT; 85 break; 86 case 'A': 87 return LEFT; 88 break; 89 case 'd': 90 return RIGHT; 91 break; 92 case 'D': 93 return RIGHT; 94 break; 95 case ' ': 96 return CHANGE; 97 break; 98 default: 99 return DEFAULT; 100 break; 101 } 102 } 103 unsigned MapNew2048::getMaxData() 104 { 105 unsigned temp=data[0][0]; 106 for(int i=0; i<HIGH; i++) 107 for(int j=0; j<LENG; j++) 108 { 109 temp=temp>data[i][j]?temp:data[i][j]; 110 } 111 return temp; 112 } 113 void MapNew2048::printMap() 114 { 115 cout<<" NEW 2 0 4 8"<<endl; 116 cout<<"-----------------------------------------------------"<<endl; 117 for(int i=0; i<HIGH; i++) 118 { 119 for(int j=0; j<LENG; j++) 120 { 121 if(data[i][j]!=0) 122 cout<<"| "<<printData[i][j]<<" "; 123 else 124 cout<<"| "<<printData[i][j][0]<<" "<<printData[i][j][7]<<" "; 125 } 126 cout<<"|"<<endl<<"-----------------------------------------------------"<<endl; 127 } 128 } 129 130 string MapNew2048::dataToPrintData(int n) 131 { 132 133 int count=0; 134 int m=pow(2,n); 135 ///str的初始化基于如下数学关系:4*4的地图下,2048游戏能合成数,理论上最大值131072(2^17),即data最大为17 136 string str {' ',m/100000+48,(m/10000)%10+48,(m/1000)%10+48,(m/100)%10+48,(m/10)%10+48,m%10+48,' '}; 137 ///对冗余0的处理 138 for(int i=1; i<7; i++) 139 { 140 if(str[i]=='0') 141 { 142 count++; 143 str[i]=' '; 144 } 145 else 146 break; 147 } 148 switch(count)///格式调整 149 { 150 case 2:///不加break会在执行完第一条语句后自动执行break 151 { 152 str[2]=str[3]; 153 str[3]=str[4]; 154 str[4]=str[5]; 155 str[5]=str[6]; 156 str[6]=' '; 157 break; 158 } 159 case 3: 160 { 161 str[3]=str[4]; 162 str[4]=str[5]; 163 str[5]=str[6]; 164 str[6]=' '; 165 break; 166 } 167 case 4: 168 { 169 str[3]=str[5]; 170 str[4]=str[6]; 171 str[5]=' '; 172 str[6]=' '; 173 break; 174 } 175 case 5: 176 { 177 str[4]=str[6]; 178 str[6]=' '; 179 break; 180 } 181 } 182 return str; 183 } 184 void MapNew2048::chooseMapSpace() 185 { 186 187 if(sta==WAIT) 188 { 189 printData[nowX][nowY][0]=printData[nowX][nowY][7]=' '; 190 dir DIR=setDir(); 191 switch(DIR) 192 { 193 case LEFT: 194 { 195 nowY--; 196 if(nowY<0) 197 nowY=LENG-1; 198 printData[nowX][nowY][0]='['; 199 printData[nowX][nowY][7]=']'; 200 break; 201 } 202 case RIGHT: 203 { 204 nowY++; 205 if(nowY>LENG-1) 206 nowY=0; 207 printData[nowX][nowY][0]='['; 208 printData[nowX][nowY][7]=']'; 209 break; 210 } 211 case UP: 212 { 213 nowX--; 214 if(nowX<0) 215 nowX=HIGH-1; 216 printData[nowX][nowY][0]='['; 217 printData[nowX][nowY][7]=']'; 218 break; 219 } 220 case DOWN: 221 { 222 nowX++; 223 if(nowX>HIGH-1) 224 nowX=0; 225 printData[nowX][nowY][0]='['; 226 printData[nowX][nowY][7]=']'; 227 break; 228 } 229 case CHANGE: 230 stateChange(); 231 break; 232 case DEFAULT: 233 { 234 printData[nowX][nowY][0]='['; 235 printData[nowX][nowY][7]=']'; 236 break; 237 } 238 } 239 } 240 } 241 void MapNew2048::moveAndAddData() 242 { 243 if(sta==READY) 244 { 245 printData[nowX][nowY][0]=printData[nowX][nowY][7]=' '; 246 dir DIR=setDir(); 247 switch(DIR) 248 { 249 case LEFT: 250 { 251 if((data[nowX][nowY]==data[nowX][nowY-1])&&(nowY>0)&&(data[nowX][nowY-1]>0)) 252 { 253 data[nowX][nowY]=0; 254 nowY--; 255 data[nowX][nowY]++; 256 printData[nowX][nowY]=dataToPrintData(data[nowX][nowY]); 257 printData[nowX][nowY][0]='('; 258 printData[nowX][nowY][7]=')'; 259 } 260 else 261 { 262 printData[nowX][nowY][0]='('; 263 printData[nowX][nowY][7]=')'; 264 } 265 mapSortToLeft(); 266 mapSortToUp(); 267 break; 268 } 269 case RIGHT: 270 { 271 if((data[nowX][nowY]==data[nowX][nowY+1])&&(nowY<LENG-1)&&(data[nowX][nowY+1]>0)) 272 { 273 data[nowX][nowY]=0; 274 nowY++; 275 data[nowX][nowY]++; 276 printData[nowX][nowY]=dataToPrintData(data[nowX][nowY]); 277 printData[nowX][nowY][0]='('; 278 printData[nowX][nowY][7]=')'; 279 } 280 else 281 { 282 printData[nowX][nowY][0]='('; 283 printData[nowX][nowY][7]=')'; 284 } 285 mapSortToLeft(); 286 mapSortToUp(); 287 break; 288 } 289 case UP: 290 { 291 if((data[nowX][nowY]==data[nowX-1][nowY])&&(nowX>0)&&(data[nowX-1][nowY]>0)) 292 { 293 data[nowX][nowY]=0; 294 nowX--; 295 data[nowX][nowY]++; 296 printData[nowX][nowY]=dataToPrintData(data[nowX][nowY]); 297 printData[nowX][nowY][0]='('; 298 printData[nowX][nowY][7]=')'; 299 } 300 else 301 { 302 printData[nowX][nowY][0]='('; 303 printData[nowX][nowY][7]=')'; 304 } 305 mapSortToUp(); 306 mapSortToLeft(); 307 break; 308 } 309 case DOWN: 310 { 311 if((data[nowX][nowY]==data[nowX+1][nowY])&&(nowX<HIGH-1)&&(data[nowX+1][nowY]>0)) 312 { 313 data[nowX][nowY]=0; 314 nowX++; 315 data[nowX][nowY]++; 316 printData[nowX][nowY]=dataToPrintData(data[nowX][nowY]); 317 printData[nowX][nowY][0]='('; 318 printData[nowX][nowY][7]=')'; 319 } 320 else 321 { 322 printData[nowX][nowY][0]='('; 323 printData[nowX][nowY][7]=')'; 324 } 325 mapSortToUp(); 326 mapSortToLeft(); 327 break; 328 } 329 case CHANGE: 330 stateChange(); 331 break; 332 case DEFAULT: 333 { 334 printData[nowX][nowY][0]='('; 335 printData[nowX][nowY][7]=')'; 336 break; 337 } 338 } 339 } 340 } 341 342 void MapNew2048::stateChange() 343 { 344 if(sta==WAIT) 345 { 346 sta=READY; 347 printData[nowX][nowY][0]='('; 348 printData[nowX][nowY][7]=')'; 349 } 350 else 351 { 352 sta=WAIT; 353 printData[nowX][nowY][0]='['; 354 printData[nowX][nowY][7]=']'; 355 } 356 } 357 358 void MapNew2048::mapSortToUp()///地图向上压缩 359 { 360 for(int n=0; n<LENG; n++) 361 { 362 for(int m=0; m<HIGH; m++) 363 { 364 if(data[m][n]==0&&m<HIGH-1) 365 { 366 for(int k=m; k<HIGH-1; k++) 367 { 368 data[k][n]=data[k+1][n]; 369 printData[k][n]=dataToPrintData(data[k][n]); 370 } 371 data[HIGH-1][n]=0; 372 } 373 } 374 } 375 ///调整时,会将printData[nowX][nowY]的标志冲掉,需要恢复一步 376 printData[nowX][nowY][0]='('; 377 printData[nowX][nowY][7]=')'; 378 } 379 void MapNew2048::mapSortToLeft()///地图向左压缩 380 { 381 for(int m=0; m<HIGH; m++) 382 { 383 for(int n=0; n<LENG; n++) 384 { 385 if(data[m][n]==0&&n<LENG-1) 386 { 387 for(int k=n; k<LENG-1; k++) 388 { 389 data[m][k]=data[m][k+1]; 390 printData[m][k]=dataToPrintData(data[m][k]); 391 } 392 data[m][LENG-1]=0; 393 } 394 } 395 } 396 printData[nowX][nowY][0]='('; 397 printData[nowX][nowY][7]=')'; 398 } 399 400 //void MapNew2048::dataCreate() 401 //{ 402 // bool dataCreateFlag1=true;///列向生成newData标志 403 // bool dataCreateFlag2=true;///横向生成newData标志 404 // for(int i=0; i<HIGH; i++) 405 // if(data[i][LENG-1]!=0) 406 // { 407 // dataCreateFlag1=false; 408 // break; 409 // } 410 // for(int i=0; i<LENG; i++) 411 // if(data[HIGH-1][i]!=0) 412 // { 413 // dataCreateFlag2=false; 414 // break; 415 // } 416 // if(!dataCreateFlag1&&!dataCreateFlag2);///不用生成newData 417 // else 418 // { 419 // unsigned max=getMaxData(); 420 // ///创建的数不大于当前地图显示的合成的最大数的一半,newData最大为max-1 421 // srand((unsigned int)time(NULL)); 422 // unsigned newData=rand()%max; 423 // if(newData==0) 424 // newData++; 425 // /**经过上述的newData生成算法,P(newData=1)=2/(max-1),P(newData=other)=1/(max-1)**/ 426 // 427 // /**下面的几行语句用于确定newData在地图中的位置**/ 428 // if(dataCreateFlag1&&!dataCreateFlag2) 429 // { 430 // srand((unsigned int)time(NULL)); 431 // int a=rand()%HIGH; 432 // data[a][LENG-1]=newData; 433 // printData[a][LENG-1]=dataToPrintData(data[a][LENG-1]); 434 // mapSortToLeft();///地图压缩 435 // } 436 // else if(!dataCreateFlag1&&dataCreateFlag2) 437 // { 438 // srand((unsigned int)time(NULL)); 439 // int b=rand()%LENG; 440 // data[HIGH-1][b]=newData; 441 // printData[HIGH-1][b]=dataToPrintData(data[HIGH-1][b]); 442 // mapSortToUp();///地图压缩 443 // } 444 // else if(dataCreateFlag1&&dataCreateFlag2) 445 // { 446 // srand((unsigned int)time(NULL)); 447 // int a=rand()%HIGH; 448 // data[a][LENG-1]=newData; 449 // printData[a][LENG-1]=dataToPrintData(data[a][LENG-1]); 450 // if(a==HIGH-1) 451 // { 452 // mapSortToLeft();///地图压缩 453 // mapSortToUp(); 454 // } 455 // else 456 // mapSortToLeft(); 457 // } 458 // } 459 //} 460 461 462 bool MapNew2048::isLive() 463 { 464 ///isLive函数基于如下数学关系:反复使用向右,向下查询(最右行只向下), 465 ///最底行只向右,可以将他的所有邻居遍历一次 466 bool liveFlag=false; 467 for(int i=0; i<HIGH; i++) 468 { 469 for(int j=0; j<LENG; j++) 470 { 471 if(i!=HIGH-1&&j!=LENG-1&&data[i][j]!=0) 472 { 473 if(data[i][j]==data[i+1][j]||data[i][j]==data[i][j+1]) 474 { 475 liveFlag=true; 476 return liveFlag; 477 } 478 } 479 else if(i==HIGH-1&&j!=LENG-1&&data[i][j]!=0) 480 { 481 if(data[i][j]=data[i+1][j]) 482 { 483 liveFlag=true; 484 return liveFlag; 485 } 486 } 487 else if(i!=HIGH-1&&j==LENG-1&&data[i][j]!=0) 488 { 489 if(data[i][j]=data[i][j+1]) 490 { 491 liveFlag=true; 492 return liveFlag; 493 } 494 } 495 } 496 } 497 return liveFlag; 498 } 499 500 int main() 501 { 502 bool gameOverFlag=false; 503 MapNew2048 map; 504 map.printMap(); 505 while(!gameOverFlag) 506 { 507 while(kbhit()) 508 { 509 system("cls"); 510 if(map.getState()==WAIT) 511 map.chooseMapSpace(); 512 else 513 { 514 map.moveAndAddData(); 515 // map.dataCreate(); 516 } 517 if(!map.isLive()) 518 gameOverFlag=true; 519 map.printMap(); 520 } 521 522 } 523 cout<<endl<<"The Max is: "<<pow(2,map.getMaxData())<<endl; 524 }
付几张游戏截图: