Easyx——2048
- 前言
- 最開始的2048(小黑框)
- 第二版的2048(C語言-Easyx)
- 最后的qq2048(C++ - Easyx)
- 2048的基本演算法介紹(第一版)
- 2048的基本函式介紹(第二版)
前言
我的第一篇blog,在我的 拖延 精益求精之下,終于誕生出來了,由于是大二上學期期末做的大作業,代碼水平還不夠高,所以CV了許多大佬的2048,經過我的一番 魔改 整合修改,所呈現出來了現在的2048,下面先展示一下最終的效果圖(●’?’●)
最開始的2048(小黑框)
最開始的2048是沒有加入圖形庫的,只是簡簡單單的在小黑框做了一個簡易到不行的2048

第二版的2048(C語言-Easyx)

因為能力有限,所以當時做出來的圖形頁面實在是慘不忍睹的丑,😭

最后的qq2048(C++ - Easyx)


2048的基本演算法介紹(第一版)
先開始第一版的介紹,但是這些演算法的思想和大致的代碼,在后面兩版都是基本不變的,
1. 亂數(2,4,8…如何去達到隨機出現的概率)
根據生成的亂數,對一定的值進行取模,達到生成一定概率的數,
例如:我們設定4出現的概率為1/9,于是可以利用系統提供的亂數函式生成一個數,然后對9取余,得到的數若大于0則在游戲面板空格處生成一個2,若余數等于0,則生成4,
void add_rand_num() {
srand((unsigned int)time(0));
int n = rand() % get_null_count(); /* 確定在何處空位置生成亂數 */
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
/* 定位待生成的位置 */
if (board[i][j] == 0 && n-- == 0) {//如果n=3,則在第三個空格生成亂數
board[i][j] = (rand() % 9 ? 2 : 4); /* 生成數字2或4,生成概率為8:1 */
return;
}
}
}
}
2. 方塊的移動
在一行中,用b[4]表示一行的一維陣列,使用兩個下標變數來遍歷列項,這里使用j和k,其中j總在k的后面,用來尋找k項后面第一個不為0的數字,而k項用于表示當前待比較的項,總是和j項之間隔著若干個數字0,或者干脆緊挨著,不失一般性,考慮往左滑動時,初始情況下j等于1,而k等于0,接著判斷j項數字是否大于0,若是,則判斷j項和k項數字的關系,
分成3種情況處理,分別是
(合并)P1: b[k]==b[j],
(移動)P2: b[k]==0
(碰撞)P3: b[k]!=0且b[k]!=b[j];
若否,則j自加1,然后繼續尋找k項后面第一個不為0的數字,
/*
* 如下四個函式,實作上下左右移動時數字面板的變化演算法
* 左和右移動的本質一樣,區別僅僅是列項的遍歷方向相反
* 上和下移動的本質一樣,區別僅僅是行項的遍歷方向相反
* 左和上移動的本質也一樣,區別僅僅是遍歷時行和列互換
*/
/* 左移 函式定義 */
void move_left() {
/* 變數i用來遍歷行項的下標,并且在移動時所有行相互獨立,互不影響 */
for (int i = 0; i < 4; ++i) {
/* 變數j為列下標,變數k為待比較(合并)項的下標,回圈進入時k<j */
for (int j = 1, k = 0; j < 4; ++j) {
if (board[i][j] > 0) /* 找出k后面第一個不為空的項,下標為j,之后分三種情況 */
{
if (board[i][k] == board[i][j]) {
/* 情況1:k項和j項相等,此時合并方塊并計分 */
board[i][k++] *= 2;
board[i][j] = 0;
if_need_add_num = 1; /* 需要生成亂數和重繪界面 */
}
else if (board[i][k] == 0) {
/* 情況2:k項為空,則把j項賦值給k項,相當于j方塊移動到k方塊 */
board[i][k] = board[i][j];
board[i][j] = 0;
if_need_add_num = 1;
}
else {
/* 情況3:k項不為空,且和j項不相等,此時把j項賦值給k+1項,相當于移動到k+1的位置 */
board[i][++k] = board[i][j];
if (j != k) {
/* 判斷j項和k項是否原先就挨在一起,若不是則把j項賦值為空(值為0) */
board[i][j] = 0;
if_need_add_num = 1;
}
}
}
}
}
}
/* 右移 函式定義 */
void move_right() {
/* 仿照左移操作,區別僅僅是j和k都反向遍歷 */
for (int i = 0; i < 4; ++i) {
for (int j = 2, k = 3; j >= 0; --j) {
if (board[i][j] > 0) {
if (board[i][k] == board[i][j]) {
board[i][k--] *= 2;
board[i][j] = 0;
if_need_add_num = 1;
}
else if (board[i][k] == 0) {
board[i][k] = board[i][j];
board[i][j] = 0;
if_need_add_num = 1;
}
else {
board[i][--k] = board[i][j];
if (j != k) {
board[i][j] = 0;
if_need_add_num = 1;
}
}
}
}
}
}
/* 上移 函式定義 */
void move_up() {
/* 仿照左移操作,區別僅僅是行列互換后遍歷*/
for (int i = 0; i < 4; ++i) {
for (int j = 1, k = 0; j < 4; ++j) {
if (board[j][i] > 0) {
if (board[k][i] == board[j][i]) {
board[k++][i] *= 2;
board[j][i] = 0;
if_need_add_num = 1;
}
else if (board[k][i] == 0) {
board[k][i] = board[j][i];
board[j][i] = 0;
if_need_add_num = 1;
}
else {
board[++k][i] = board[j][i];
if (j != k) {
board[j][i] = 0;
if_need_add_num = 1;
}
}
}
}
}
}
/* 下移 函式定義 */
void move_down() {
/* 仿照左移操作,區別僅僅是行列互換后遍歷,且j和k都反向遍歷 */
for (int i = 0; i < 4; ++i) {
for (int j = 2, k = 3; j >= 0; --j) {
if (board[j][i] > 0) {
if (board[k][i] == board[j][i]) {
board[k--][i] *= 2;
board[j][i] = 0;
if_need_add_num = 1;
}
else if (board[k][i] == 0) {
board[k][i] = board[j][i];
board[j][i] = 0;
if_need_add_num = 1;
}
else {
board[--k][i] = board[j][i];
if (j != k) {
board[j][i] = 0;
if_need_add_num = 1;
}
}
}
}
}
}
3. 游戲頁面的展示refresh_show();
根據數字長度、漢字長度、空格長度…一個個嘗試出來的
/* 重繪界面 函式定義 */
void refresh_show() {
clear_screen();
printf("\n\n\n\n");
printf(" GAME: 2048 \n");
printf(" --------------------------------------------------");
/* 繪制方格和數字 */
printf("\n\n ┌────┬────┬────┬────┐\n");
int i;
for (i = 0; i < 4; ++i) {
printf(" │");
int j;
for (j = 0; j < 4; ++j) {
if (board[i][j] != 0) {
if (board[i][j] < 10) { //當元素小于10時,列印
printf(" %d │", board[i][j]);
}
else if (board[i][j] < 100) { //當元素大于10小于100時列印
printf(" %d │", board[i][j]);
}
else if (board[i][j] < 1000) { //當元素大于100小于1000時列印
printf(" %d│", board[i][j]);
}
else if (board[i][j] < 10000) { //當元素大于1000小于10000時列印
printf("%4d│", board[i][j]);
}
else {
int n = board[i][j];
int k;
for (k = 1; k < 20; ++k) {
n = n >> 1;
if (n == 1) {
printf("2^%02d│", k); //超過四位的數字用2的冪形式表示,如2^13形式
break;
}
}
}
}
else printf(" │");
}
if (i < 3) {
printf("\n ├────┼────┼────┼────┤\n");
}
else {
printf("\n └────┴────┴────┴────┘\n");
}
}
printf("\n");
printf(" --------------------------------------------------\n");
printf(" [W]:UP [S]:DOWN [A]:LEFT [D]:RIGHT [Q]:EXIT");
}
4. 記錄最高分
Write_max(int); Read_max(); max_score;
static const char* score_max = "2048游戲-最高記錄.txt";
用檔案來記錄最高分并在游戲開始呼叫出最高分的記錄
5.獲取空位置
根據隨機函式生成一個數,然后對空格數取余,然后在第余數個空格出生成數字,
int get_null_count() {
int n = 0;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
board[i][j] == 0 ? ++n : 1; //n為空格計數器
}
}
return n;
}
6.判斷游戲是否結束
/* 檢查游戲是否結束 函式定義 */
void check_game_over() {
int i;
for (i = 0; i < 4; ++i) {
int j;
for (j = 0; j < 3; ++j) {
/* 橫向和縱向比較挨著的兩個元素是否相等,若有相等則游戲不結束 */
if (board[i][j] == board[i][j + 1] || board[j][i] == board[j + 1][i]) {
if_game_over = 0;
return;
}
}
}
if_game_over = 1;
}
還有零零碎碎的一些重繪函式、重置游戲的函式、介紹規則的、滑鼠的按鍵的……之后我把原始碼上傳到GitHub上,到時候放鏈接,
2048的基本函式介紹(第二版)
第二版的偽代碼展示
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/277752.html
標籤:其他
上一篇:C1能力認證任務訓練攻略詳解
下一篇:C語言-9(三子棋)
