花了一个深夜,才用C语言写了一个2048游戏雏形
12年我畢業的第二個月工資,我就買了一個IPAD,然后在IPAD上下了一個2048游戲,玩起來非常爽。
然后這幾天看到好幾個公眾號都發了自己寫這個游戲的代碼,然后我自己也想試試,所以就有了這篇文章,寫代碼還是很有意思的。
針對這個游戲我寫幾個比較關鍵的點
— — 在Linux 下輸入不用按回車鍵也就能獲取鍵值
我們平時輸入的時候,需要按?Enter ,getchar 才能獲取鍵值,所以這個需要設置下
如果設置為 false,就可以不輸入回車就能獲取鍵值,還需要注意我們有時候按下 Ctrl+c 退出程序,需要在這里的回調函數重新設置,要不然在正常的界面輸入會出現問題。
— —?隨機值的設置
我們需要在畫盤上插入隨機值,所以就需要隨機值生成的方法,C 庫里面就有這個隨機函數,但是需要設置下。
隨機值的設置需要遵循規則如下
//要取得[a,b)的隨機整數,使用(rand() % (b-a))+ a (結果值含a不含b)。
//要取得[a,b]的隨機整數,使用(rand() % (b-a+1))+ a (結果值含a和b)。
//要取得(a,b]的隨機整數,使用(rand() % (b-a))+ a + 1 (結果值不含a含b)。
/*初始化幾個數字在鍵盤上*/ int add_random(void) {static bool initialized = false;int pos,data,i;/*隨機數需要設置種子,用時間來做隨機數的種子*/if (!initialized) {srand(time(NULL));initialized = true;}/*檢測如果原來的位置有數據了,就不能在原來的數據上加數據*/for(i=0;i<16;i++){pos = rand()%15;if(array_core[pos] != 0)continue;elsebreak;}/*獲取?0~4 的隨機值*/data = rand()%(4-0+1)+ 0;/*再通過數組把這個數值轉換成我們需要的隨機數*/place_xy(pos,array_rand[data]);return (0); }— — 清除屏幕
我們需要循環顯示畫盤,所以需要每次顯示之前都需要清除屏幕,關鍵代碼如下
— — 幾個關鍵的數組
我們需要幾個關鍵的數組來協助我們計算,這部分根據自己的代碼要求來設置。
第一個數組是鍵盤,我們的數據都是在鍵盤上顯示的,因為 2048 是4個數字,所以中間要預留4個空格出來。
d_xy 數組是用來保存這16個數字的位置的坐標數組,有了這些坐標,就可以知道如何擺放這些數值了。
另外兩個數組的作用已經在注釋里面寫清楚了。
/*數組*/ char board[] =" ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n";const int d_xy[16] = {25,30,35,40, 71,76,81,86, 117,122,127,132, 163,168,173,178}; const int array_rand[5] = {2,4,4,2,8};/*隨機數值*/ int array_core[16] = {0};/*用來保存鍵盤上的16個數字*/— —?最關鍵的移動算法
先說下我們鍵盤的位置
我沒有用二維數組,后面想了下,如果用二維數組的話會方便很多,而且算法可能也會方便很多,特別是用到矩陣變換。
— 下移
從下往上的每一列,把相鄰相同的數字加起來,放到下面那個位置,然后把上面的位置清0。
把0的數值往上移動,把數字往下移動。
其他方向的移動規則跟這個一樣的思路
代碼實現
/*下移*/ int move_down(void) {int i=0,j=0,x=0,y=0;int temp[4] = {0};/*1、合并相鄰相同的兩個元素*//*2、把0元素移動到最上面*/for(x=0;x<4;x++){for(y=x,i=0;y<=12+x;i++,y+=4){temp[i] = array_core[y];}/*合并相鄰的兩個非0值*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == temp[j-1] && temp[j-1] != 0){temp[j] = 2*temp[j-1];temp[j-1] = 0;}}}/*把0往上移動*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == 0 && temp[j-1] != 0){temp[j] = temp[j-1];temp[j-1] = 0;}}}for(y=x,i=0;y<=12+x;i++,y+=4){array_core[y] = temp[i];}}/*在鍵盤上顯示*/for(i=0;i<16;i++)place_xy(i,array_core[i]);add_random();return (0); }— — 完整代碼如下
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <termios.h> #include <stdbool.h> #include <stdint.h> #include <time.h> #include <signal.h>/*函數聲明*/ int show_board(void); void teset(void); int move_down(void); /*宏定義*/ #define X_LENGTH (13)/*數組*/ char board[] =" ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n \ | | | | |\n \ ---------------------\n";const int d_xy[16] = {25,30,35,40, 71,76,81,86, 117,122,127,132, 163,168,173,178}; const int array_rand[5] = {2,4,4,2,8};/*隨機數值*/ int array_core[16] = {0};/*用來保存鍵盤上的16個數字*/int move_left(void) {int i=0,j=0,x=0,y=0;int temp[4] = {0};/*1、合并相鄰相同的兩個元素*//*2、把0元素移動到最下面*/for(y=0;y<=12;y+=4){for(x=y,i=0;x<=3+y;i++,x++){temp[i] = array_core[x];}/*上移*/for(i=0;i<4;i++){for(j=0;j<3;j++){if(temp[j] == temp[j+1] && temp[j+1] != 0){temp[j] = 2*temp[j+1];temp[j+1] = 0;}}}/*上移*/for(i=0;i<4;i++){for(j=0;j<3;j++){if(temp[j] == 0 && temp[j+1] != 0){temp[j] = temp[j+1];temp[j+1] = 0;}}}for(x=y,i=0;x<=3+y;i++,x++){array_core[x] = temp[i];}}/*在鍵盤上顯示*/for(i=0;i<16;i++){place_xy(i,array_core[i]);}add_random();return (0); }int move_right(void) {int i=0,j=0,x=0,y=0;int temp[4] = {0};/*1、合并相鄰相同的兩個元素*//*2、把0元素移動到最上面*/for(y=0;y<=12;y+=4){for(x=y,i=0;x<=3+y;i++,x++){temp[i] = array_core[x];}/*合并相鄰的兩個非0值*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == temp[j-1] && temp[j-1] != 0){temp[j] = 2*temp[j-1];temp[j-1] = 0;}}}/*把0往上移動*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == 0 && temp[j-1] != 0){temp[j] = temp[j-1];temp[j-1] = 0;}}}for(x=y,i=0;x<=3+y;i++,x++){array_core[x] = temp[i];}}/*在鍵盤上顯示*/for(i=0;i<16;i++)place_xy(i,array_core[i]);add_random();return (0); }/*上移動*/ int move_up(void) {int i=0,j=0,x=0,y=0;int temp[4] = {0};/*1、合并相鄰相同的兩個元素*//*2、把0元素移動到最下面*/for(x=0;x<4;x++){for(y=x,i=0;y<=12+x;i++,y+=4){temp[i] = array_core[y];}/*上移*/for(i=0;i<4;i++){for(j=0;j<3;j++){if(temp[j] == temp[j+1] && temp[j+1] != 0){temp[j] = 2*temp[j+1];temp[j+1] = 0;}}}/*上移*/for(i=0;i<4;i++){for(j=0;j<3;j++){if(temp[j] == 0 && temp[j+1] != 0){temp[j] = temp[j+1];temp[j+1] = 0;}}}for(y=x,i=0;y<=12+x;i++,y+=4){array_core[y] = temp[i];}}/*在鍵盤上顯示*/for(i=0;i<16;i++){place_xy(i,array_core[i]);}add_random();return (0); } /*下移*/ int move_down(void) {int i=0,j=0,x=0,y=0;int temp[4] = {0};/*1、合并相鄰相同的兩個元素*//*2、把0元素移動到最上面*/for(x=0;x<4;x++){for(y=x,i=0;y<=12+x;i++,y+=4){temp[i] = array_core[y];}/*合并相鄰的兩個非0值*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == temp[j-1] && temp[j-1] != 0){temp[j] = 2*temp[j-1];temp[j-1] = 0;}}}/*把0往上移動*/for(i=3;i>=0;i--){for(j=3;j>0;j--){if(temp[j] == 0 && temp[j-1] != 0){temp[j] = temp[j-1];temp[j-1] = 0;}}}for(y=x,i=0;y<=12+x;i++,y+=4){array_core[y] = temp[i];}}/*在鍵盤上顯示*/for(i=0;i<16;i++)place_xy(i,array_core[i]);add_random();return (0); }/*測試函數*/ void teset(void) { #if 0int i = 0;for(i = 0;i<16;i++){place_xy(i,i+1);} #else/*計算偏移值*/int i = 0;for(i = 0;i<strlen(board);i++){if(board[i] == '\n')printf(" %d ",i+3); } printf("\n"); #endif }int place_xy(int pos,int data) {if(data == 0){board[d_xy[pos]] = 0x20; /*十位*/board[d_xy[pos] +1 ] = 0x20; /*個位*/board[d_xy[pos] +2 ] = 0x20; /*個位*/board[d_xy[pos] +3 ] = 0x20; /*個位*/}else if(data < 10){board[d_xy[pos]] = data + 48;/*如果數值是0,就不顯示*/}else if(data < 100){board[d_xy[pos]] = data/10 + 48; board[d_xy[pos] +1] = data%10 + 48; }else if(data < 1000){board[d_xy[pos]] = data/100 + 48; board[d_xy[pos] +1] = data%100/10 + 48; board[d_xy[pos] +2] = data%100%10 + 48; }else{board[d_xy[pos]] = data/1000 + 48; /*千位*/board[d_xy[pos] +1] = data%1000/100 + 48; /*百位*/board[d_xy[pos] +2 ] = data%1000%100/10 + 48; /*十位*/board[d_xy[pos] +3 ] = data%1000%100%10 + 48; /*個位*/}/*把數字保存到鍵盤里面去*/array_core[pos] = data;/*顯示鍵盤*/show_board();return(0); }/*初始化幾個數字在鍵盤上*/ int add_random(void) {static bool initialized = false;int pos,data,i;/*隨機數需要設置種子,用時間來做隨機數的種子*/if (!initialized) {srand(time(NULL));initialized = true;}/*檢測如果原來的位置有數據了,就不能在原來的數據上加數據*/for(i=0;i<16;i++){pos = rand()%15;if(array_core[pos] != 0)continue;elsebreak;}data = rand()%(4-0+1)+ 0;place_xy(pos,array_rand[data]);return (0); }/*初始化一個鍵盤*/ int show_board(void) {printf("\033[H\033[J");/*清空屏幕 但是并不是每一個terminal都會生效*/printf("%s",board);printf("[ ←,↑,→,↓ or q ]\n");return(0); }/*設置之后不用按下回車就可以接收到字符*/ void setBufferedInput(bool enable) {static bool enabled = true;static struct termios old;struct termios new;if (enable && !enabled) {// restore the former settingstcsetattr(STDIN_FILENO,TCSANOW,&old);// set the new stateenabled = true;} else if (!enable && enabled) {// get the terminal settings for standard inputtcgetattr(STDIN_FILENO,&new);// we want to keep the old setting to restore them at the endold = new;// disable canonical mode (buffered i/o) and local echonew.c_lflag &=(~ICANON & ~ECHO);// set the new settings immediatelytcsetattr(STDIN_FILENO,TCSANOW,&new);// set the new stateenabled = false;} }/*需要檢測ctrl+c 按鍵,要不然輸入變成一直輸入了不轉回來,鍵盤就輸入不了了*/ void signal_callback_handler(int signum) {printf(" TERMINATED \n");setBufferedInput(true);printf("\033[?25h\033[m");exit(signum); }int main() {char c;bool success;memset(array_core,0,sizeof(array_core)/sizeof(array_core[0]));/*在鍵盤上添加三個隨機數*/add_random();add_random();add_random();/*顯示鍵盤*/show_board();setBufferedInput(false);teset();/*注冊信號量*/signal(SIGINT, signal_callback_handler);while(true){c=getchar();//printf("%d",c);#if 1if (c == -1){puts("\nError! Cannot read keyboard input!");break;}switch(c) {case 97: // 'a' keycase 104: // 'h' keycase 68: // left arrowsuccess = move_left(); break;case 100: // 'd' keycase 108: // 'l' keycase 67: // right arrowsuccess = move_right(); break;case 119: // 'w' keycase 107: // 'k' keycase 65: // up arrowsuccess = move_up(); break;case 115: // 's' keycase 106: // 'j' keycase 66: // down arrow//printf("move_down\n");success = move_down(); break;default: success = false;}#endif/*判斷是否退出*/if (c=='q') {printf(" 退出? (y/n) \n");c=getchar();if (c=='y') {break;}}usleep(150000);}setBufferedInput(true);//teset();return (0); }— —?運行起來
— —?程序缺陷
1、沒有分數判斷
2、沒有最終結果判斷,比如所有格子都不能移動了,需要判斷勝負。
3、隨機值加入也比較隨意
4、沒有設置格子顏色,比較單調
5、有一些你不知道的bug。
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
嵌入式Linux
微信掃描二維碼,關注我的公眾號?
總結
以上是生活随笔為你收集整理的花了一个深夜,才用C语言写了一个2048游戏雏形的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql sever 插入数据
- 下一篇: 计算机开机提示dll,电脑开机提示找不到