一、規則創新ios
勝利條件:達成2048dom
難度變化:玩家能夠經過調整難度條來控制隨機池(二、四、八、16)中各個數出現的機率,同時也會改變分數的加成比例ide
移動觸發:每次移動後會從隨機池中按照機率隨機選取一個數,將其隨機放置在一個空餘位置上函數
分數計算:總分=基礎分+加成分,基礎分+=合併的數值,加成分+=隨機生成的數值*加成比例ui
二、遊戲效果this
先將該項目分爲遊戲入口、主窗口設計與遊戲邏輯三個主要模塊,再在這三個模塊的基礎上繼續細分,分割成若干個小的功能模塊,最後逐一實現。由MainWindow與GameLogic兩個類分別實現主界面的顯示功能與遊戲的實現邏輯。spa
程序入口較爲簡單,故不贅述。設計
主窗口設計主要實現棋盤數據的顯示與顏色變化、分數與難度的顯示、檢測方向鍵並鏈接進入遊戲邏輯的入口。3d
遊戲邏輯是整個項目的核心部分,主要實現整個遊戲的邏輯判斷,根據主窗口提供的難度計算出難度係數與隨機池各個數據出現機率。code
文件具體分爲gamelogic.cpp、main.cpp與mainwindow.cpp三個.cpp文件,gamelogic.h、mainwindow.h兩個.h文件與一個mainwindow.ui文件。
一、程序入口:main.cpp
1 #include "mainwindow.h" 2 #include <QApplication> 3 4 int main(int argc, char *argv[]) 5 { 6 QApplication a(argc, argv); 7 MainWindow w; 8 w.show(); 9 10 return a.exec(); 11 }
若是想進行人員管理與登錄的拓展可改成如下代碼,可自行設計login登陸規則:
1 #include "mainwindow.h" 2 #include <QApplication> 3 4 int main(int argc, char *argv[]) 5 { 6 QApplication a(argc, argv); 7 MainWindow w; 8 w.show(); 9 10 return a.exec(); 11 }
二、主窗口設計:mainwindow.cpp/.h/.ui
2.1 mainwindow.ui
2.2 mainwindow.h
1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QKeyEvent> 6 #include <QDebug> 7 #include <QMessageBox> 8 #include <QTextBrowser> 9 #include "gamelogic.h" 10 11 namespace Ui { 12 class MainWindow; 13 } 14 15 class MainWindow : public QMainWindow 16 { 17 Q_OBJECT 18 19 public: 20 GameLogic* game; 21 explicit MainWindow(QWidget *parent = 0); 22 ~MainWindow(); 23 void initAll(); 24 void showMessage(); 25 void showBroad(); 26 void keyPressEvent(QKeyEvent *event); 27 void changeColor(QLabel* label, int num); 28 29 private slots: 30 void on_pushButton_start_clicked(); 31 32 void on_pushButton_close_clicked(); 33 34 void on_horizontalSlider_valueChanged(int value); 35 36 private: 37 Ui::MainWindow *ui; 38 }; 39 40 #endif // MAINWINDOW_H
2.3 mainwindow.cpp(代碼共177行,摺疊)
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 #include "gamelogic.h" 4 5 MainWindow::MainWindow(QWidget *parent) : 6 QMainWindow(parent), 7 ui(new Ui::MainWindow) 8 { 9 game = new GameLogic; 10 ui->setupUi(this); 11 showBroad(); 12 } 13 14 MainWindow::~MainWindow() 15 { 16 delete ui; 17 } 18 19 void MainWindow::initAll() 20 { 21 game->initAll(); 22 on_horizontalSlider_valueChanged(ui->horizontalSlider->value()); 23 } 24 25 26 void MainWindow::on_pushButton_start_clicked() 27 { 28 ui->pushButton_start->setText("從新開始"); 29 initAll(); 30 31 game->createNum(); 32 game->createNum(); 33 game->setGameStart(true); 34 35 showBroad(); 36 showMessage(); 37 } 38 39 void MainWindow::on_pushButton_close_clicked() 40 { 41 this->close(); 42 } 43 44 void MainWindow::on_horizontalSlider_valueChanged(int value) 45 { 46 value = ui->horizontalSlider->value(); 47 ui->label_showGradeUpCoefficient->setText(QString::number(value*2)+"%"); 48 game->setGradeUpCoefficient((float)ui->horizontalSlider->value()/100); 49 50 if (20 > value) ui->label_showDifficult->setText("簡單"); 51 else if(40 > value) ui->label_showDifficult->setText("正常"); 52 else if(60 > value) ui->label_showDifficult->setText("困難"); 53 else if(80 > value) ui->label_showDifficult->setText("地獄"); 54 else ui->label_showDifficult->setText("混沌"); 55 } 56 57 void MainWindow::keyPressEvent(QKeyEvent *event) 58 { 59 if(!game->getGameStart()) return; 60 switch(event->key()) 61 { 62 case Qt::Key_Up: game->process(CMD_UP); break; 63 case Qt::Key_Down: game->process(CMD_DOWN); break; 64 case Qt::Key_Left: game->process(CMD_LEFT); break; 65 case Qt::Key_Right: game->process(CMD_RIGHT); break; 66 } 67 showBroad(); 68 showMessage(); 69 switch(game->judge()) 70 { 71 case STAT_PROCESS: break; 72 case STAT_WIN: QMessageBox::information(NULL,"2048","大吉大利,今晚吃雞!"); break; 73 case STAT_LOSE: QMessageBox::information(NULL,"2048","再接再礪,永不放棄!"); break; 74 } 75 } 76 77 void MainWindow::showMessage() 78 { 79 ui->label_showGrade->setText(QString::number(game->getGrade())); 80 ui->label_showGradeBasic->setText(QString::number(game->getGradeBasic())); 81 ui->label_showGradeUp->setText(QString::number(game->getGradeUp())); 82 ui->label_showStep->setText(QString::number(game->getStep())); 83 } 84 85 void MainWindow::showBroad() 86 { 87 //第一行 88 if(game->getData(0,0)) ui->label_00->setText(QString::number(game->getData(0,0))); 89 else ui->label_00->setText(" "); 90 if(game->getData(0,1)) ui->label_01->setText(QString::number(game->getData(0,1))); 91 else ui->label_01->setText(" "); 92 if(game->getData(0,2)) ui->label_02->setText(QString::number(game->getData(0,2))); 93 else ui->label_02->setText(" "); 94 if(game->getData(0,3)) ui->label_03->setText(QString::number(game->getData(0,3))); 95 else ui->label_03->setText(" "); 96 changeColor(ui->label_00, game->getData(0,0)); 97 changeColor(ui->label_01, game->getData(0,1)); 98 changeColor(ui->label_02, game->getData(0,2)); 99 changeColor(ui->label_03, game->getData(0,3)); 100 101 //第二行 102 if(game->getData(1,0)) ui->label_10->setText(QString::number(game->getData(1,0))); 103 else ui->label_10->setText(" "); 104 if(game->getData(1,1)) ui->label_11->setText(QString::number(game->getData(1,1))); 105 else ui->label_11->setText(" "); 106 if(game->getData(1,2)) ui->label_12->setText(QString::number(game->getData(1,2))); 107 else ui->label_12->setText(" "); 108 if(game->getData(1,3)) ui->label_13->setText(QString::number(game->getData(1,3))); 109 else ui->label_13->setText(" "); 110 changeColor(ui->label_10, game->getData(1,0)); 111 changeColor(ui->label_11, game->getData(1,1)); 112 changeColor(ui->label_12, game->getData(1,2)); 113 changeColor(ui->label_13, game->getData(1,3)); 114 115 //第三行 116 if(game->getData(2,0)) ui->label_20->setText(QString::number(game->getData(2,0))); 117 else ui->label_20->setText(" "); 118 if(game->getData(2,1)) ui->label_21->setText(QString::number(game->getData(2,1))); 119 else ui->label_21->setText(" "); 120 if(game->getData(2,2)) ui->label_22->setText(QString::number(game->getData(2,2))); 121 else ui->label_22->setText(" "); 122 if(game->getData(2,3)) ui->label_23->setText(QString::number(game->getData(2,3))); 123 else ui->label_23->setText(" "); 124 changeColor(ui->label_20, game->getData(2,0)); 125 changeColor(ui->label_21, game->getData(2,1)); 126 changeColor(ui->label_22, game->getData(2,2)); 127 changeColor(ui->label_23, game->getData(2,3)); 128 129 //第四行 130 if(game->getData(3,0)) ui->label_30->setText(QString::number(game->getData(3,0))); 131 else ui->label_30->setText(" "); 132 if(game->getData(3,1)) ui->label_31->setText(QString::number(game->getData(3,1))); 133 else ui->label_31->setText(" "); 134 if(game->getData(3,2)) ui->label_32->setText(QString::number(game->getData(3,2))); 135 else ui->label_32->setText(" "); 136 if(game->getData(3,3)) ui->label_33->setText(QString::number(game->getData(3,3))); 137 else ui->label_33->setText(" "); 138 changeColor(ui->label_30, game->getData(3,0)); 139 changeColor(ui->label_31, game->getData(3,1)); 140 changeColor(ui->label_32, game->getData(3,2)); 141 changeColor(ui->label_33, game->getData(3,3)); 142 } 143 144 //改變方塊的StyleSheet 145 void MainWindow::changeColor(QLabel* label, int num) 146 { 147 label->setAlignment(Qt::AlignCenter); 148 switch (num) 149 { 150 case 2: label->setStyleSheet("background-color: rgb(238,228,218);" 151 "font:bold 75 30pt ""微軟雅黑"""); break; 152 case 4: label->setStyleSheet("background-color: rgb(237,224,200);" 153 "font:bold 75 30pt ""微軟雅黑"""); break; 154 case 8: label->setStyleSheet("background-color: rgb(242,177,121);" 155 "font:bold 75 30pt ""微軟雅黑"""); break; 156 case 16: label->setStyleSheet("background-color: rgb(245,150,100);" 157 "font:bold 75 30pt ""微軟雅黑"""); break; 158 case 32: label->setStyleSheet("background-color: rgb(245,125,95);" 159 "font:bold 75 30pt ""微軟雅黑"""); break; 160 case 64: label->setStyleSheet("background-color: rgb(245,95,60);" 161 "font:bold 75 30pt ""微軟雅黑"""); break; 162 case 128: label->setStyleSheet("background-color: rgb(237,207,114);" 163 "font:bold 75 25pt ""微軟雅黑"""); break; 164 case 256: label->setStyleSheet("background-color: rgb(237,204,97);" 165 "font:bold 75 25pt ""微軟雅黑"""); break; 166 case 512: label->setStyleSheet("background-color: rgb(237,204,97);" 167 "font:bold 75 25pt ""微軟雅黑"""); break; 168 case 1024: label->setStyleSheet("background-color: rgb(237,204,97);" 169 "font:bold 75 20pt ""微軟雅黑"""); break; 170 case 2048: label->setStyleSheet("background-color: rgb(237,204,97);" 171 "font:bold 75 20pt ""微軟雅黑"""); break; 172 default: label->setStyleSheet("background-color: rgb(238,228,218);" 173 "font:bold 75 40pt ""微軟雅黑"""); break; 174 } 175 }
① 初始化全部數據,鎖定檢測:
void initAll();
② 經過按鈕開始或結束遊戲,而且可隨時調節遊戲難度:
void on_pushButton_start_clicked();
void on_pushButton_close_clicked();
void on_horizontalSlider_valueChanged(int value);
③ 顯示界面與各種信息,根據各個方塊的數值來調整遊戲顯示畫面:
void showMessage();
void showBroad();
void changeColor(QLabel* label, int num);
④ 檢測方向鍵,執行成員變量game的邏輯函數:
void keyPressEvent(QKeyEvent *event);
三、遊戲邏輯:gamelogic.cpp/.h
3.1 gamelogic.h
1 #ifndef GAMELOGIC_H 2 #define GAMELOGIC_H 3 4 #include <iostream> 5 6 #define ROW 4 7 #define COL 4 8 9 enum CMD 10 { 11 CMD_UP, 12 CMD_DOWN, 13 CMD_LEFT, 14 CMD_RIGHT, 15 }; 16 17 enum STAT 18 { 19 STAT_WAIT, 20 STAT_PROCESS, 21 STAT_WIN, 22 STAT_LOSE, 23 }; 24 25 class GameLogic 26 { 27 public: 28 GameLogic(); 29 bool createNum(); 30 void process(int cmd); 31 int judge(); 32 void initAll(); 33 void calProb(); 34 35 void moveUp(); 36 void moveDown(); 37 void moveLeft(); 38 void moveRight(); 39 40 bool getGameStart(); 41 void setGameStart(bool); 42 void setGradeUpCoefficient(float); 43 int getData(int,int); 44 int getGrade(); 45 int getGradeBasic(); 46 int getGradeUp(); 47 int getStep(); 48 49 private: 50 bool gameStart; 51 int data[4][4]; 52 float grade; 53 int gradeBasic; 54 float gradeUp; 55 int step; 56 float gradeUpCoefficient; 57 int prob2; 58 int prob4; 59 int prob8; 60 int prob16; 61 }; 62 63 #endif // GAMELOGIC_H
3.2 gamelogic.cpp(代碼共299行,摺疊)
1 #include "gamelogic.h" 2 #include "ui_mainwindow.h" 3 4 #include <random> 5 #include <iostream> 6 #include <vector> 7 #include <qDebug> 8 using namespace std; 9 10 GameLogic::GameLogic() 11 { 12 initAll(); 13 } 14 15 void GameLogic::initAll() 16 { 17 for(int i=0; i<ROW; i++) 18 { 19 for(int j=0; j<COL; j++) 20 { 21 data[i][j] = 0; 22 } 23 } 24 gameStart = false; 25 grade = 0; 26 gradeBasic = 0; 27 gradeUp = 0; 28 step = 0; 29 gradeUpCoefficient = 0; 30 31 prob2 = 0; 32 prob4 = 0; 33 prob8 = 0; 34 prob16 = 0; 35 } 36 37 void GameLogic::calProb() 38 { 39 qDebug() << "gradeUpCoefficient:" << gradeUpCoefficient ; 40 if(0.6 > gradeUpCoefficient) // 0->0.6 41 { 42 prob2 = 80-gradeUpCoefficient*100*0.5; // 80%->50% 43 prob4 = 100; // 20%->50% 44 prob8 = 0, prob16 = 0; // 0 45 qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ; 46 } 47 else if(0.8 > gradeUpCoefficient) // 0.6->0.8 48 { 49 prob2 = 80-gradeUpCoefficient*100*0.5; // 50%->40% 50 prob4 = 50+prob2; // 50% 51 prob8 = 100; // 0->10% 52 prob16 = 0; // 0 53 qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ; 54 } 55 else if(1 >= gradeUpCoefficient)// 0.8->1.0 56 { 57 prob2 = 40; // 40% 58 prob4 = -10+gradeUpCoefficient*100*0.5+prob2; // 30%->40% 59 prob8 = -10+gradeUpCoefficient*100*0.25+prob4; // 10%->15% 60 prob16 = 100; // 0->5% 61 qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ; 62 } 63 } 64 65 bool GameLogic::createNum() 66 { 67 vector<int> indexSpace; 68 for(int i=0; i<ROW; i++) 69 { 70 for(int j=0; j<COL; j++) 71 { 72 if(!data[i][j]) 73 { 74 indexSpace.push_back(i*4+j); 75 } 76 } 77 } 78 if(!indexSpace.empty()) 79 { 80 int randNum = rand()%100; 81 int randPlace = rand()%indexSpace.size(); 82 int chooseNum = -1; 83 84 calProb(); 85 //qDebug() << "randNum:" << randNum; 86 //qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ; 87 if (prob2 > randNum) chooseNum = 2; 88 else if(prob4 > randNum) chooseNum = 4; 89 else if(prob8 > randNum) chooseNum = 8; 90 else if(prob16 > randNum) chooseNum = 16; 91 int x = indexSpace[randPlace]/4; 92 int y = indexSpace[randPlace]%4; 93 //qDebug("---------- %d %d----------",x,y); 94 data[x][y] = chooseNum; 95 gradeUp += 2*chooseNum*gradeUpCoefficient; 96 grade = gradeBasic + gradeUp; 97 return true; 98 } 99 else 100 { 101 return false; 102 } 103 } 104 105 void GameLogic::process(int cmd) 106 { 107 switch(cmd) 108 { 109 case CMD_UP: moveUp(); break; 110 case CMD_DOWN: moveDown(); break; 111 case CMD_LEFT: moveLeft(); break; 112 case CMD_RIGHT: moveRight(); break; 113 } 114 createNum(); 115 createNum(); 116 step++; 117 } 118 119 void GameLogic::moveUp() 120 { 121 for(int j=0; j<COL; j++) 122 { 123 //取出全部非零元素 124 int t[10] = {0}; 125 int cnt = 0; 126 for(int i=0; i<ROW; i++) 127 if(data[i][j]) 128 t[cnt++] = data[i][j]; 129 130 for(int k=0; k<cnt-1; k++) 131 { 132 if(t[k]==t[k+1]) 133 { 134 gradeBasic += t[k]; 135 t[k] *= 2; 136 t[k+1] = 0; 137 } 138 } 139 //將合併後的非零元素填入data中 140 int n = 0; 141 for(int k=0; k<cnt; k++) 142 { 143 if(t[k]) 144 data[n++][j] = t[k]; 145 } 146 //尾部補零 147 for(; n<ROW; n++) 148 { 149 data[n][j] = 0; 150 } 151 } 152 } 153 154 void GameLogic::moveDown() 155 { 156 for(int j=0; j<COL; j++) 157 { 158 int t[10]; 159 int cnt = 0; 160 161 for(int i=ROW-1; i>=0; i--) 162 if(data[i][j]) t[cnt++] = data[i][j]; 163 164 for(int k=0; k<cnt-1; k++) 165 { 166 if(t[k]==t[k+1]) 167 { 168 gradeBasic += t[k]; 169 t[k] *= 2; 170 t[k+1] = 0; 171 } 172 } 173 174 int n = ROW-1; 175 for(int k=0; k<cnt; k++) 176 { 177 if(t[k]) data[n--][j] = t[k]; 178 } 179 180 for(; n>=0; n--) 181 { 182 data[n][j] = 0; 183 } 184 } 185 } 186 187 void GameLogic::moveLeft() 188 { 189 for(int i=0; i<ROW; i++) 190 { 191 int t[10]; 192 int cnt = 0; 193 for(int j=0; j<COL; j++) 194 if(data[i][j]) t[cnt++] = data[i][j]; 195 196 for(int k=0; k<cnt-1; k++) 197 { 198 if(t[k]==t[k+1]) 199 { 200 gradeBasic += t[k]; 201 t[k] *= 2; 202 t[k+1] = 0; 203 } 204 } 205 206 int n = 0; 207 for(int k=0; k<cnt; k++) 208 { 209 if(t[k]) data[i][n++] = t[k]; 210 } 211 212 for(; n<COL; n++) 213 { 214 data[i][n] = 0; 215 } 216 217 } 218 } 219 220 void GameLogic::moveRight() 221 { 222 for(int i=0; i<ROW; i++) 223 { 224 int t[10]; 225 int cnt = 0; 226 for(int j=COL-1; j>=0; j--) 227 if(data[i][j]) t[cnt++] = data[i][j]; 228 229 for(int k=0; k<cnt-1; k++) 230 { 231 if(t[k]==t[k+1]) 232 { 233 gradeBasic += t[k]; 234 t[k] *= 2; 235 t[k+1] = 0; 236 } 237 } 238 239 int n = COL-1; 240 for(int k=0; k<cnt; k++) 241 { 242 if(t[k]) data[i][n--] = t[k]; 243 } 244 245 for(; n>=0; n--) 246 { 247 data[i][n] = 0; 248 } 249 250 } 251 } 252 253 int GameLogic::judge() 254 { 255 //贏得遊戲 256 for (int i=0; i<ROW; i++) 257 { 258 for (int j=0; j<COL; j++) 259 { 260 if (data[i][j] == 2048) 261 { 262 return STAT_WIN; 263 } 264 } 265 } 266 //橫向檢查 267 for (int i=0; i<ROW; i++) 268 { 269 for (int j=0; j<COL-1; j++) 270 { 271 if (!data[i][j] || (data[i][j] == data[i][j+1])) 272 { 273 return STAT_PROCESS; 274 } 275 } 276 } 277 //縱向檢查 278 for (int j=0; j<COL; j++) 279 { 280 for (int i=0; i<ROW-1; i++) 281 { 282 if (!data[i][j] || (data[i][j] == data[i+1][j])) 283 { 284 return STAT_PROCESS; 285 } 286 } 287 } 288 //不符合上述兩種情況,遊戲結束 289 return STAT_LOSE; 290 } 291 292 bool GameLogic::getGameStart(){return gameStart;} 293 void GameLogic::setGameStart(bool flag){gameStart = flag;} 294 void GameLogic::setGradeUpCoefficient(float i){gradeUpCoefficient = i;} 295 int GameLogic::getData(int i, int j){return data[i][j];} 296 int GameLogic::getGrade(){return grade;} 297 int GameLogic::getGradeBasic(){return gradeBasic;} 298 int GameLogic::getGradeUp(){return gradeUp;} 299 int GameLogic::getStep(){return step;}
① 宏定義棋盤行列數:#define ROW 4; #define COL 4;
② 枚舉定義指令與狀態:enum CMD... enum STAT...
③ 定義成員變量:
遊戲狀態:bool gameStart;
棋盤規格:int data[ROW][COL];
分數統計:float grade;
int gradeBasic;
float gradeUp;
float gradeUpCoefficient;
當前步數:int step;
隨機數機率:int prob2;
int prob4;
int prob8;
int prob16;
④ 定義成員函數:
初始化數據:void initAll();
創造隨機數:bool createNum();
狀態斷定:int judge();
機率計算:void calProb();
遊戲過程:void process(int cmd);
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
數據處理:bool getGameStart();
void setGameStart(bool);
void setGradeUpCoefficient(float);
int getData(int,int);
int getGrade();
int getGradeBasic();
int getGradeUp();
int getStep();