大部分同窗學習C語言編程之後不知道能經過什麼樣的項目才能夠鍛鍊本身的思惟功力,2048相信你們都應該熟悉,無論是手機上仍是網頁版的相信你們都玩過,這個簡單的控制檯版本的遊戲是我曾經在偉易達上班時一個嵌入式應用遊戲部門的大佬設計的,適合於喜歡用C語言寫一些簡易的遊戲的朋友,邏輯性很強。編程
C/C++的學習裙【七一二 二八四 七零五 】,不管你是小白仍是進階者,是想轉行仍是想入行均可以來了解一塊兒進步一塊兒學習!裙內有開發工具,不少乾貨和技術資料分享!(點擊藍字進入)工具
在最初的遊戲, 它始於一個空4 x 4遊戲板。學習
1)在空位置的遊戲板上,每一輪遊戲產生一個「2」或「4」隨機的數字。開發工具
2)接下來,玩家輸入的上移,下移,左移或右移命令移動塊。兩個相鄰塊相同的號碼,如果Q,能夠組合成一個塊數量2Q。ui
3)若是沒有空間產生一個新的數字塊,玩家則game over。spa
4)想贏得遊戲,玩家須要產生一塊2048數字塊。設計
固然,這些遊戲的邏輯不是你們悶着腦子就能空想出來的,它必定有很規範的說明文檔,由專業的人來書寫,最後軟件工程師參考對應的文檔編寫本身的代碼調試
原版本以下:code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <conio.h> //num #define FALSE 0 #define TRUE 1 #define EMPTY_CELL 0 #define GMAE_ROW 4 #define GMAE_COL 4 //GameState #define STATE_SELECT 0 #define STATE_PREPARE 1 #define STATE_PALYING 2 #define STATE_EXIT 3 //GameMode #define MODE_NONE 0 #define MODE_NORMAL 1 #define MODE_DEBUG 2 //Select Index #define INDEX_MAXNUM 3 #define INDEX_NORMAL 0 #define INDEX_DEBUG 1 #define INDEX_EXIT 2 //Command #define COM_LEFT 'a' #define COM_RIGHT 'd' #define COM_UP 'w' #define COM_DOWN 's' #define COM_QUIT 'q' //direction #define DIR_HEAD 0xe0 #define KEY_UP 0xe048 #define KEY_DOWN 0xe050 #define KEY_LEFT 0xe04b #define KEY_RIGHT 0xe04d #define ESC 0x1B #define ENTER 0x0D //type typedef unsigned int Uint; typedef unsigned short Ushort; typedef unsigned char Uchar; //declaration static void GM_Init(void); static void GM_End(void); static Uint GM_SelectInit(void); static Uint GM_SelectHandle(void); static Uint GM_SelectEnd(void); static Uint GM_PrepareInit(void); static Uint GM_PrepareHandle(void); static Uint GM_PrepareEnd(void); static Uint GM_PlayingInit(void); static Uint GM_PlayingHandle(void); static Uint GM_PlayingEnd(void); static Uint GM_SelectHandleEnter(void); static Uint GM_SelectHandleEsc(void); static void GM_PrintSelectMode(void); static void GM_RandAddOneNum(void); static Uchar GM_FromFileAddNum(void); static Uchar GM_InputAddOneNum(void); static Uchar GM_NotMoreMove(void); static void GM_PrintBoard(void); static Uchar GM_CheckWin2048(void); static Uchar GM_PlayingPull(void); static Uchar GM_CombineRight(Uint *array, int num); static Uchar GM_CombineLeft(Uint *array, int num); static Uchar GM_MoveRight(Uint *array, int num); static Uchar GM_MoveLeft (Uint *array, int num); //struct typedef struct gameinfo { Uint Board[GMAE_ROW][GMAE_COL]; Uchar GameState; Uchar GameMode; Uchar StateSelectIndex; Uint PlayingCommand; }GameInfo, *P_GameInfo; GameInfo GM; int main(void) { GM_Init(); while(1) { switch(GM.GameState) { case STATE_SELECT: GM_SelectHandle(); break; case STATE_PREPARE: GM_PrepareHandle(); break; case STATE_PALYING: GM_PlayingHandle(); break; case STATE_EXIT: goto GAME_EXIT; default: break; } } GAME_EXIT: GM_End(); return 0; } static void GM_Init(void) { memset(&GM, 0, sizeof(GameInfo)); srand((int)time(NULL)); GM_SelectInit(); } static void GM_End(void) { memset(&GM, 0, sizeof(GameInfo)); fflush(stdin); printf("\nCommand [q] can quit\n"); while('q' != getch()); } static Uint GM_SelectInit(void) { GM.GameState = STATE_SELECT; GM.StateSelectIndex = INDEX_NORMAL; GM_PrintSelectMode(); } static Uint GM_SelectHandle(void) { GM_PrintSelectMode(); fflush(stdin); Uchar ch1 = getch(); if( ENTER == ch1) { GM_SelectHandleEnter(); } else if( ESC == ch1 ) { GM_SelectEnd(); GM.GameState = STATE_EXIT; } else if ( DIR_HEAD == ch1) { Uchar ch2 = getch(); Ushort Key = (ch1 << 8)&0xff00 | ch2; switch(Key) { case KEY_UP: GM.StateSelectIndex = (GM.StateSelectIndex + INDEX_MAXNUM - 1) % INDEX_MAXNUM; break; case KEY_DOWN: GM.StateSelectIndex = (GM.StateSelectIndex + 1) % INDEX_MAXNUM; break; default: break; } } } static Uint GM_SelectEnd(void){} static Uint GM_PrepareInit(void) { Uchar OldState = GM.GameState; GM.GameState = STATE_PREPARE; //from STATE_SELECT --> STATE_PREPARE if(STATE_SELECT == OldState) { if(MODE_NORMAL == GM.GameMode) { GM_RandAddOneNum(); GM_RandAddOneNum(); } else { GM_FromFileAddNum(); } } //from STATE_PALYING --> STATE_PREPARE else { if(MODE_NORMAL == GM.GameMode) { GM_RandAddOneNum(); } else { GM_PrintBoard(); while(FALSE == GM_InputAddOneNum()); } } GM_PrintBoard(); } static Uint GM_PrepareHandle(void) { if(TRUE != GM_NotMoreMove()) { GM_PrepareEnd(); GM_PlayingInit(); } else { printf("Game Over!\n"); GM.GameState = STATE_EXIT; } } static Uint GM_PrepareEnd(void){} static Uint GM_PlayingInit(void) { GM.GameState = STATE_PALYING; printf( "PULL: [a]LEFT [d]RIGHT [w]UP [s]DOWN [q]QUIT\n" ); printf( "Command: "); fflush(stdout); } static Uint GM_PlayingHandle(void) { fflush(stdin); GM.PlayingCommand = getch(); switch(GM.PlayingCommand) { case COM_LEFT: case COM_RIGHT: case COM_UP: case COM_DOWN: if( FALSE == GM_PlayingPull()) { printf("[Error] invalid direction\n"); printf( "Command: "); } else { if( TRUE == GM_CheckWin2048() ) { GM_PrintBoard(); printf("you win !\n"); GM.GameState = STATE_EXIT; } else { GM_PlayingEnd(); GM_PrepareInit(); } } break; case COM_QUIT: printf("Bye !\n"); GM.GameState = STATE_EXIT; break; default: printf("[Error] Command is a, d, w, s, q \n"); printf( "Command: "); fflush(stdout); break; } //GM_PrintBoard(); } static Uint GM_PlayingEnd(void) { GM.PlayingCommand = 0; } static Uint GM_SelectHandleEnter(void) { switch(GM.StateSelectIndex) { case INDEX_NORMAL: case INDEX_DEBUG: if(INDEX_NORMAL == GM.StateSelectIndex) { GM.GameMode = MODE_NORMAL; } else { GM.GameMode = MODE_DEBUG; } GM_SelectEnd(); GM_PrepareInit(); break; case INDEX_EXIT: GM_SelectEnd(); GM.GameState = STATE_EXIT; break; default: printf("error\n"); break; } } static Uint GM_SelectHandleEsc(void){} static void GM_PrintSelectMode(void) { system("cls"); printf("# - - - - - - - - #\n"); printf("# welcome to 2048 #\n"); printf("# - - - - - - - - #\n"); printf(" MODU SELECT \n"); printf("\n "); printf(GM.StateSelectIndex==INDEX_NORMAL?"-->NORMAL":" NORMAL"); printf("\n "); printf(GM.StateSelectIndex==INDEX_DEBUG? "-->DEBUG ":" DEBUG "); printf("\n "); printf(GM.StateSelectIndex==INDEX_EXIT? "-->EXIT ":" EXIT "); } static void GM_RandAddOneNum(void) { int row, col; while (1) { row = rand() % GMAE_ROW; col = rand() % GMAE_COL; if ( GM.Board[row][col] == EMPTY_CELL ) { GM.Board[row][col] = ((rand() % 2) + 1) * 2; break; } } } static Uchar GM_FromFileAddNum(void) { FILE *infp; Uchar tmp[6],tmp1; Uchar ret = 0; Uchar i,j; if(infp = fopen("map.txt", "rb")) { for(i = 0; i < GMAE_ROW * GMAE_COL; i++) { j = 0; memset(tmp, 0, sizeof(tmp)); while(1) { if(!fread(&tmp[j], 1, 1, infp)) ret |= 0x02; if(tmp[j] == ' ' || tmp[j] == '\n' || tmp[j] == 0) break; j++; } *(&GM.Board[0][0]+i) = atoi((const char *)tmp); } } else { ret |= 0x01; } if(NULL != infp) { fclose(infp); } if(ret != 0) { printf("read map txt fail\n"); } return ret; } static Uchar GM_InputAddOneNum(void) { int row, col, value; int ret = TRUE; printf("please input add one num!\n"); printf("Row,Col,Value :"); fflush(stdout); fflush(stdin); scanf("%d,%d,%d", &row, &col, &value); if(row >= GMAE_ROW || row < 0) { printf("[Error] Row is between 0 and %d !\n", GMAE_ROW-1); ret = FALSE; } if(col >= GMAE_COL || col < 0) { printf("[Error] Col is between 0 and %d !\n", GMAE_COL-1); ret = FALSE; } if(ret == TRUE && GM.Board[row][col] != 0) { printf("[Error] ( %d , %d ) is occupied!\n", row, col); ret = FALSE; } if(value != 2 && value != 4) { printf("[Error] Cell Value is either 2 or 4\n"); ret = FALSE; } if(ret == TRUE) { GM.Board[row][col] = value; } return ret; } static Uchar GM_NotMoreMove(void) { int NotMoreMove = TRUE; int row, col; for ( row = 0; row < GMAE_ROW; row++) { for ( col = 0; col < GMAE_COL; col++) { if(GM.Board[row][col] == 0) { NotMoreMove = FALSE; break; } if( col+1 < GMAE_COL && GM.Board[row][col] == GM.Board[row][col+1]) { NotMoreMove = FALSE; break; } if( row+1 < GMAE_ROW && GM.Board[row][col] == GM.Board[row+1][col]) { NotMoreMove = FALSE; break; } } if(FALSE == NotMoreMove) break; } return NotMoreMove; } static void GM_PrintBoard(void) { int row, col; system("cls"); printf("# - - - - - - - - #\n"); printf("# welcome to 2048 #\n"); printf("# - - - - - - - - #\n"); for ( row = 0; row < GMAE_ROW; row++) { for ( col = 0; col < GMAE_COL; col++) { printf(" + - -", GM.Board[row][col]); } printf(" +\n"); for ( col = 0; col < GMAE_COL; col++) { if(0 == GM.Board[row][col]) printf(" | "); else printf(" |%4d", GM.Board[row][col]); } printf(" |\n"); } printf(" + + + + + + + + + + + + + \n"); } static Uchar GM_CheckWin2048(void) { int row,col; for ( row = 0; row < GMAE_ROW; row++) { for ( col = 0; col < GMAE_COL; col++) { if( GM.Board[row][col] == 2048 ) { return TRUE; } } } return FALSE; } static Uchar GM_PlayingPull(void) { //GMAE_ROW 行 4 //GMAE_COL 列 4 int index; int col, row; Uchar PullFlag = FALSE; Uint array[GMAE_ROW > GMAE_COL? GMAE_ROW:GMAE_COL]; //******************COM_LEFT******************* if( COM_LEFT == GM.PlayingCommand) for ( row = 0; row < GMAE_ROW; row++) { PullFlag |= GM_MoveLeft( (Uint *)GM.Board[row], GMAE_COL ); PullFlag |= GM_CombineLeft( (Uint *)GM.Board[row], GMAE_COL ); PullFlag |= GM_MoveLeft( (Uint *)GM.Board[row], GMAE_COL ); } //******************COM_RIGHT****************** else if( COM_RIGHT == GM.PlayingCommand) for ( row = 0; row < GMAE_ROW; row++) { PullFlag |= GM_MoveRight( (Uint *)GM.Board[row], GMAE_COL ); PullFlag |= GM_CombineRight( (Uint *)GM.Board[row], GMAE_COL ); PullFlag |= GM_MoveRight( (Uint *)GM.Board[row], GMAE_COL ); } //******************COM_UP********************* else if( COM_UP == GM.PlayingCommand) for ( col = 0; col < GMAE_COL; col++) { for ( row = 0; row < GMAE_ROW; row++) { array[row] = GM.Board[row][col]; } //a col move Left PullFlag |= GM_MoveLeft( (Uint *)array, GMAE_ROW ); PullFlag |= GM_CombineLeft( (Uint *)array, GMAE_ROW ); PullFlag |= GM_MoveLeft( (Uint *)array, GMAE_ROW ); //write a col for ( row = 0; row < GMAE_ROW; row++) { GM.Board[row][col] = array[row]; } } //******************COM_DOWN****************** else if( COM_DOWN == GM.PlayingCommand) for ( col = 0; col < GMAE_COL; col++) { //read a col for ( row = 0; row < GMAE_ROW; row++) { array[row] = GM.Board[row][col]; } //a col move right PullFlag |= GM_MoveRight( (Uint *)array, GMAE_ROW ); PullFlag |= GM_CombineRight( (Uint *)array, GMAE_ROW ); PullFlag |= GM_MoveRight( (Uint *)array, GMAE_ROW ); //write a col for ( row = 0; row < GMAE_ROW; row++) { GM.Board[row][col] = array[row]; } } return PullFlag; } static Uchar GM_CombineLeft(Uint *array, int num) { int i; Uchar CombineFlag = FALSE; for ( i = 0; i < num-1; i++ ) { if( array[i] != 0 && array[i] == array[i+1] ) { array[i] *= 2; array[i+1] = 0; CombineFlag = TRUE; } } return CombineFlag; } static Uchar GM_CombineRight(Uint *array, int num) { int i; Uchar CombineFlag = FALSE; for ( i = num-1; i >= 1; i-- ) { if( array[i] != 0 && array[i] == array[i-1] ) { array[i] *= 2; array[i-1] = 0; CombineFlag = TRUE; } } return CombineFlag; } static Uchar GM_MoveRight(Uint *array, int num) { int i; int index = num - 1; Uchar moveflg = FALSE; for(i = num-1; i >= 0; i--) { if(array[i] != 0) { if(array[i] != array[index]) { array[index] = array[i]; moveflg = TRUE; } index--; } } while(index != -1) { array[index] = 0; index--; } return moveflg; } static Uchar GM_MoveLeft(Uint *array, int num) { int i; int index = 0; Uchar moveflg = FALSE; for(i = 0; i < num; i++) { if(array[i] != 0) { if(array[i] != array[index]) { array[index] = array[i]; moveflg = TRUE; } index++; } } while(index != num) { array[index] = 0; index++; } return moveflg; } 4、運行結果遊戲主菜單界面,經過方向鍵選擇,分別有NORMAL(正常進行遊戲)、DEBUG(調試模式)、EXIT(退出遊戲)按回車鍵進入對應的模式。用字母a、d、w、s、q分別代替左右上下以及退出鍵。若是最後遊戲成功了,則會提示成功,若是失敗則會退出程序。詳細的遊戲邏輯可經過代碼以及文檔進行了解。