2048遊戲 - C語言不引入圖形庫簡單實現
阿新 • • 發佈:2020-09-09
宣告:本程式絕大部分屬於原創,互動部分參考了部落格園 Judge Young的原創文章 遊戲2048原始碼 - C語言控制檯介面版,
作者Judge Young的演算法思想非常值得參考,感謝作者的分享
附上文章連結:https://www.cnblogs.com/judgeyoung/p/3760515.html
演算法總體思想:(請結合思維導圖觀看,移動合併演算法篇幅較大,部分放到函式註釋)
- 遊戲主體抽象:將遊戲數字面板抽象為一個二維陣列,0代表空格。
- 移動合併演算法:把每一行/列同等對待,只研究一行/列的移動和合並演算法,通過遍歷來實現所有行/列的移動合併演算法。
- 遊戲結束條件:分為三種情況,主動退出、遊戲失敗和遊戲勝利。
- 隨機數生成:尋找出空格,平均概率生成2 / 4。
- 介面顯示:利用清屏再列印,達到介面重新整理效果。
- 計分系統:遊戲結束時,將所有格子中數字相加得到最終分數。
- 矩陣翻轉:為了減少程式碼量與複用函式,提高練習效果,這裡犧牲了部分效率。
- 備註:移動合併演算法也可以通過矩陣翻轉90度達到更好的函式複用效果,但效率更低。
- 再備註:函式宣告處有一個撤回功能,可以利用old_squares做出來,但由於作者嫌麻煩所以沒有做。
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <time.h> #define N 4 //矩陣大小為N * N #define Max 2048 //勝利條件 int squares[N][N]; //遊戲矩陣 int sum; //遊戲積分 int old_squares[N][N]; //之前一步操作的矩陣 void GameStart(void); //遊戲開始介面 void Print(void); //列印介面、計分 void Operator(char op); //對使用者互動進行處理 int Operated(void); //判斷矩陣是否發生變化 void Copy(void); //備份上一步的矩陣 void MoveUp(int op); //上移方格 void MoveLeft(int op); //左移方塊 void Transpose(int op); //矩陣翻轉 int GameOver(char op); //遊戲結束:失敗,退出和遊戲勝利(需設定條件) int Win(void); //判斷遊戲勝利 //void Recall(void); //撤回功能 void Random(void); //生成隨機數 int HasNull(void); //判斷矩陣存在空白位置 void PrintSum(void); //計算遊戲積分並列印 int main(void) { char op = ' '; GameStart(); Random(); Operator(op); while (!GameOver(op)) { Copy(); while (!Operated()) { op = getch(); Operator(op); } Random(); system("cls"); Print(); } system("pause"); return 0; } //初始化遊戲引數 void GameStart(void) { int i, j; sum = 0; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { squares[i][j] = 0; old_squares[i][j] = 0; } } printf("Press any key to start the game.\n"); } //列印矩陣 void Print(void) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { if (squares[i][j] == 0) { printf(" \t"); continue; } printf("%d\t", squares[i][j]); } printf("\n\n"); } printf("\n"); printf("(W)Up (S)Down (A)Left (D)Right\n"); printf(" (Q)Quit (R)Recall\n\n"); } void Operator(char op) { switch (op) { case 'w': case 'W': MoveUp(1); break; case 'a': case 'A': MoveLeft(1); break; case 's': case 'S': MoveUp(0); break; case 'd': case 'D': MoveLeft(0); break; default: break; } } int Operated(void) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { if (old_squares[i][j] != squares[i][j]) return 1; } } return 0; } void Copy(void) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { old_squares[i][j] = squares[i][j]; } } } //在一行中,使用兩個下標變數來遍歷列項,假設使用j和k,其中j總在k的後面,用來尋找k項後面第一個不為0的數字,而k項用於表示當前待比較的項,總是和j項之間隔著若干個數字0,或者乾脆緊挨著。 void MoveUp(int op) { int i, j, k; if (op == 0) Transpose(0); for (i = 0; i < N; i++) { for (j = 1, k = 0; j < 4; j++) { if (squares[j][i] > 0) { /* 找出k後面第一個不為空的項,下標為j,之後分三種情況 */ //合併 if (squares[k][i] == squares[j][i]) { squares[k][i] = 2 * squares[k][i]; squares[j][i] = 0; k++; } //移動 else if (squares[k][i] == 0) { squares[k][i] = squares[j][i]; squares[j][i] = 0; } //碰撞 else { squares[k + 1][i] = squares[j][i]; if (j != k + 1) { /* 原先兩數不挨著 */ squares[j][i] = 0; } k++; } } } } if (op == 0) Transpose(0); } void MoveLeft(int op) { int i, j, k; if (op == 0) Transpose(1); for (i = 0; i < N; i++) { for (j = 1, k = 0; j < 4; j++) { if (squares[i][j] > 0) { //合併 if (squares[i][k] == squares[i][j]) { squares[i][k] = 2 * squares[i][k]; squares[i][j] = 0; k++; } //移動 else if (squares[i][k] == 0) { squares[i][k] = squares[i][j]; squares[i][j] = 0; } //碰撞 else { squares[i][k + 1] = squares[i][j]; if (j != k + 1) { /* 原先兩數不挨著 */ squares[i][j] = 0; } k++; } } } } if (op == 0) Transpose(1); } void Transpose(int op) { int i, j, temp = 0; //左右翻轉 if (op == 1) { for (i = 0; i < N; i++) { for (j = 0; j < N / 2; j++) { temp = squares[i][j]; squares[i][j] = squares[i][N - j - 1]; squares[i][N - j - 1] = temp; } } } //上下翻轉 else { for (i = 0; i < N; i++) { for (j = 0; j < N / 2; j++) { temp = squares[j][i]; squares[j][i] = squares[N - j - 1][i]; squares[N - j - 1][i] = temp; } } } } int GameOver(char op) { int i, j; if (op == 'q' || op == 'Q') printf("You have quit the game! GameOver!\n"); else if (Win()) printf("Congratulation! You win!\n"); else { if (HasNull()) return 0; for (i = 1; i < N; i++) { for (j = 0; j < N; j++) { //任意兩個相鄰的單元值相同,遊戲繼續 if (squares[i - 1][j] == squares[i][j]) return 0; if (squares[j][i - 1] == squares[j][i]) return 0; } } } PrintSum(); return 1; } int Win(void) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { if (squares[i][j] == Max) return 1; } } return 0; } //在矩陣中隨機位置生成數字2/4 void Random(void) { int sitex, sitey; sitex = rand() % 4; sitey = rand() % 4; while (squares[sitex][sitey] != 0) { sitex = rand() % 4; sitey = rand() % 4; } //生成2的概率是2/3,生成4的概率是1/3 if (rand() % 3 == 0) squares[sitex][sitey] = 4; else squares[sitex][sitey] = 2; } int HasNull(void) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { if (squares[i][j] == 0) return 1; } } return 0; } void PrintSum(void) { int i, j; for (i = 0; i < N; i++) for (j = 0; j < N; j++) sum += squares[i][j]; printf("Game Over! Your total score is: %d! \n", sum); }