2048遊戲也算是風靡一時的益智遊戲。其背後實現的邏輯比較簡單,代碼量不算多,而且趣味性強,適合作為有語言基礎的童鞋來加強編程訓練。
我們提供給大家的 2048 小遊戲,不要求大家精通 C 語言,也不會涉及到指針的使用,
只需要學會以下幾個知識點即可:
會使用變量(int、char)和二維數組;
能夠懂得函數的聲明和使用;
掌握 C 語言的分支結構(if-else 和 switch 語句)和循環結構(while 和 fo() 循環);
設計 2048 小遊戲的主要目的是讓大家夯實 C 語言基礎,訓練編程思維,培養解決問題的思路,領略多姿多彩的 C 語言。
前 言
遊戲截圖:
C語言
遊戲實現原理:1.使用終端圖形庫文件curses繪製終端里的圖形。
2.使用一個二維數組保存4 x 4 空格中的變量。
鍵盤輸入控制移動,經過邏輯判斷,二維數組數據變化。
3.二維數組數據變化後交給圖形函數顯示出來。
庫文件curses介紹:
curses是一種終端圖形繪製庫,利用curses可以在終端中繪製多種圖形。
簡單demo
#include
#include
int main(){
initscr();
border(0,0,0,0,0,0,0,0);
move(5,15);
printw("%s","hello world");
refresh();
char ch=getch();
endwin();
return 0;
}
深入學習請查詢相關資料。
C語言
2048實現代碼分析
根據2048實現原理,代碼要實現的主要有三件事:
圖形繪製遊戲邏輯操作圖形加載邏輯結果
主程序代碼如下:
2048 C語言版代碼分析
//-------------頭文件--------------------//
#include
#include
#include
#include
#include
#include
//--------------------------------------//
//------------------全局變量-------------------------------
// 遊戲主介面是一個 4*4 的 16 宮格,使用二維數組進行表示,用 0 表示空格
int a[4][4] = {0};// 16
宮格中空格的個數
int empty;
// 涉及到新產生的數字的位置的兩個變量
int old_y, old_x;
//所有的C語言代碼就是在這三個函數中
int main(){
//初始化函數
init();
//遊戲運行時函數
play();
//結束函數,清屏
//endwin()來關閉
curses 模式.
endwin();
return 0;
}
main()函數代碼分析
頭文件+全局變量
頭文件中包含的庫文件如下:
標準輸入輸出
設計到內存操作函數
繪製圖形庫文件
時間函數
睡眠函數庫文件
信號相關操作庫文件
C語言
主函數代碼
主函數中共有三個子函數,其中複雜的為前兩個,第三個為curses關閉的函數,沒有任何邏輯。init()函數的作用是遊戲準備,繪圖函數等。play()函數是遊戲運行的主要邏輯函數。
C語言
下面分別分析init()函數和play()函數的實現。
init()函數
必要的curses庫開啟函數
設置遊戲開始時空格數為15
產生兩個隨機數x、y作為第一個數字的位置下標
調用draw()函數來繪製圖形
C語言
所有的圖形繪製都是依靠draw()函數來完成的。下面來分析該函數。
draw()函數
使用兩個雙層循環繪製4*4窗格。
調用draw_one()函數將全局變量數組a[][]中的數據顯示在空格中。
C語言
draw()_one()函數
將a[][]中的數字轉換成c[]中的字符
循環c[]輸出字符,並顯示在圖形中
C語言
play()函數代碼
play函數是整個遊戲的主題函數,負責移動,判斷等邏輯。遊戲的邏輯主要分兩個步驟來完成,以向左移動為例來說明:
C語言
1、循環16個窗口,從(0,0)開始,如果(0,1)和(0,0)相同,則兩個相加,並將(0,1)置為0。然後繼續判斷(0,2)和現在的(0,0)是否相同,相同則相加到(0,0)中。直到(0,0)右邊都判斷完成結束。
2、以上步驟只是完成一個窗口(0,0)的判斷,使用循環將16個都完成相加。
3、所有的完成相加之後可能的情況是下面這樣的,還須將所有的數字都移到左邊。以圖中(1,1)為例,循環到(1,1)時,判斷左邊的窗口是否為0,如果為0,則向左移動一個,繼續判斷左邊是否為0,直到移動到最左邊。
C語言
具體的代碼分析:
使用一個死循環while(1)來循環接收輸入,判斷等。
ch=getch()接收輸入,switch case來判斷輸入的內容。
C語言
具體分析其中一個,以向左移動為例:
循環判斷每一個空格中的數字
如果為0,則繼續下一次循環;如果不為0,則判斷其右邊的格子中數字是否相同。
如果右邊格子中的數字和當前格子中相同,那麼相加,繼續判斷右邊的右邊直到數組到底。
所有相同的數字都相加結束之後,將所有的數字整體向左移動。
case 68: // 左移方向鍵
for(y = 0; y < 4; y++)
for(x = 0; x < 4; )
{ //如果a[y][x]中的值為0,則跳過該次循環
if(a[y][x] == 0)
{
x++; continue;
}
else //如果a[y][x]中的值不為0,則 { //循環的思想是,以傳入的坐標為基點,向右邊搜索,如果右邊的和基點相等,則將兩個點相加 //相加之後繼續向後搜索,還有相等的則繼續相加。直到超出範圍而退出。 //下一次循環繼續搜索。
for(i = x + 1; i < 4; i++)
{ //判斷a[y][x+1],即該空格的右邊的對應位置是否為0,如果為0則退出本次循環
if(a[y][i] == 0)
{ continue;
} else //如果不為0,則判斷是否相等,如果相等則相加,然後將後面一個置0,退出循環 { if(a[y][x] == a[y][i])
{
a[y][x] += a[y][i];
a[y][i] = 0; //當有相加產生之後,會多出一個空格。這裡體現空格的減少。
empty++; break;
} else
{ break;
}
}
} //當該次循環退出之前,只是完成了該基點的一次搜索,所以要向右邊移動一個,繼續下一次的業務。
x = i;
}
} //當所有的相加都完成之後,要將數據整體向左移動,體現在數據全都左移。
//將所有的數值向左移
for(y = 0; y < 4; y++) for(x = 0; x < 4; x++)
{ //如果該位為0,則不動,因為需要移動的是有數值的項
if(a[y][x] == 0)
{ continue;
}
else //如果該為不為0,則向左移動一位,前提是判斷該位的左邊是空位
{ //如果前面是左邊是空位,則移動到空位上,繼續判斷左邊的左邊是不是空位,如果是則繼續移動,直到所有的都移動完成。
for(i = x; (i > 0) && (a[y][i-1] == 0); i--)
{
a[y][i-1] = a[y][i];
a[y][i] = 0; //一旦移動過,就將move置1,方便後面空格中生成新的數據
move = 1;
}
}
} break;
C語言
當switch case結束之後,要完成當前狀態的檢驗:
判斷空格的剩餘數,如果剩餘小於等於0,則遊戲結束
如果不等於0,則判斷空格是否等於上次或者有移動,兩者有一個成立,就要生成新的數字
產生新數字的下標a[x][y]中的x、y,直到該x、y對應的數組a[][]上為空值時才成功
判斷該x、y是否為最佳出現地點
生成不等於0或者2的時候退出。(不明白的這裡的邏輯)
在第四步中使用了函數cnt_value()來判斷下一個數字出現的最佳地點,後面單獨分析。
C語言
cnt_value()
該函數主要選擇出下一個數字的最佳出現地點,原則就是周圍的空格數最多。
以上一步驟產生的x、y為起點,算出其左右的空格數。
循環所有的空格,統計其周圍8個空格的空格數。如果有空格數大於起點的,則生成新的數字。
cnt_one()為具體計算某一個空格周圍8個格子的空格數的函數。邏輯簡單,不做具體分析。
cnt_one()
C語言
整個邏輯都很正常,除了這最後的cnt_value()函數,這裡要找出四周空格最多的一個窗口,而直接將隨機產生的窗口作為周圍空格最多的就不合理了(max並非最多)。後面只要出現空格數大於該窗口的就選為下一個數字出現的窗格,實際獲取的並未最多空格的下標。應該是統計出4*4窗格中周圍空格數最多的,然後在最多的窗口處出現下一個數字。
C語言
加C/C++學習交.流群,免費獲取C語言、C++學習資料,學習路線指導和梳理,更有進階乾貨的直播免費學習權限 ,都是大牛帶飛 讓你少走很多的彎路的 群...號是 546912356