(updating...)
Reference blog: https://blog.csdn.net/qq_39151563/article/details/104283217
Because it is too long to put in one article, it is divided into several parts.
(there may be 10 articles =. =)
Previous articles:
2048 game series - Overview
2048 game series - first draft of function module [matrix operation]
2048 game series - second draft of function module [keyboard input]
This section describes how to generate new numbers based on conditions.
1, Determine whether to add
-
Before we add a new number, we need to judge whether to add it. For example, when the following matrix grid slides upward, there is no change before and after the move, so it is not necessary to add a new number:
int grid[4][4] = { {0,1,2,3}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} };
-
How to judge whether the movement is effective provides two ideas:
2.1 compare each element before and after grid movement: if each element is the same, it can be judged that the movement is invalid. On the contrary, as long as one element is different, the movement is valid. (this logic is implemented in the main function)2.2. Judge during the movement: if the number is moved, the movement is valid; otherwise, the movement is invalid. (this logic is implemented in the Move() function)
2, Add new number logic
After knowing that the movement is valid, the logic of adding a new number is as follows:
2.1 find a vacancy
- If EmptyBlock = 0, there is no vacancy
- Using the random function of EGE
random(n);//Returns an integer from 0 to n-1
Suppose the grid is as follows:
int grid[4][4] = { {0,1,2,3}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} };
EmptyBlock should be 16-3 = 13, so we have 13 positions to choose from. random(EmptyBlock)+1 just returns an integer from 1 to 13 randomly
2.2 code
(little knowledge: multidimensional arrays are mapped into one dimension in computer storage)
//Add new number //There are many debugging comments that can be deleted void addnum(int n) { while(n--)//Add n { EmptyBlock = CalculateEmpty(); //cout << "addnum Test" << endl; if(EmptyBlock<=0) { //cout << "addnum EmptyBlock = " << EmptyBlock << endl; //cout << "addnum Test1" << endl; return; } int cnt = random(EmptyBlock)+1;//Randomly get a number within the number of spaces //Cout < < find the first "< < CNT < < space" < < endl; //cout << "cnt = " << cnt << endl; int *p = &grid[0][0]-1;//Record the first address of the matrix, because the following p will be returned when it is found++ //cout << "n = "<< n <<endl; for(int i=0; i<4&&cnt; i++) for(int j=0; j<4&&cnt; j++) { if(grid[i][j]==0 && cnt)//If there are spaces and cnt is valid { //cout << "cnt = " << cnt << endl; cnt--;//Find one, scratch one } p++;//p points to the next one for judgment } //At the end of the loop, p points to the space we randomly specified before *p = (random(10)==0)?2:1;// The probability of 0.1 is 2 and the probability of 0.9 is 1 //Cout < < insert successfully < < endl; //*p = (random(10)==0)+1;// It's OK to write like this EmptyBlock--; } }
Test code:
Test results (2 numbers were successfully added at random):
3, Integrate into the code in the previous article
3.1 minor changes to procedures
-
Matrix set to 0
int grid[4][4] = {0};//Matrix set to 0
-
ShowInfo() print information function
//Display information - centralize some information to be printed void ShowInfo() { cout << "dir = " << dir << endl; cout<< "EmptyBlock = " << CalculateEmpty() << endl; PrintGrid(); }
-
Judge whether the movement is effective (the first idea used)
bool flag = false; //Move flag bit int tempGrid[4][4]; //Temporary array int i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) tempGrid[i][j] = grid[i][j]; //cout << "tempGrid[4][4] = " << endl; // for(i=0; i<4; i++) // { // for(j=0; j<4; j++) // cout << tempGrid[i][j] << " "; // cout << endl; // } // cout << endl; Move(dir);//move //compare for(i=0; i<4; i++) for(j=0; j<4; j++) if(grid[i][j]!=tempGrid[i][j]) { flag = true; break; } if(flag) { addnum(1); cout << "Effective movement" << endl; } //else Cout < < invalid move < < endl; ShowInfo(); dir = -1;//Set dir to invalid, otherwise the console will always refresh
3.2 all codes
#include <iostream> #include "graphics.h" using namespace std; //Test matrix int grid[4][4] = {0 // {1,2,3,4}, // {4,5,6,7}, // {7,8,9,10}, // {1,1,1,0} }; int EmptyBlock = 4 ; //Number of spaces int dir = -1; // 0-left, 1-up, 2-right, 3-down //Print function void PrintGrid() { for(int i=0; i<4; i++) { for(int j=0; j<4; j++) cout << grid[i][j] << " "; cout << endl; } cout << endl; } //Calculate space function int CalculateEmpty() { int cnt = 0; for(int i=0; i<4; i++) for(int j=0; j<4; j++) if(grid[i][j]==0) cnt++; return cnt; } //display information void ShowInfo() { cout << "dir = " << dir << endl; cout<< "EmptyBlock = " << CalculateEmpty() << endl; cout << "grid[4][4] = " << endl; PrintGrid(); } //Moving function static int x0[4] = {0, 0, 3, 0}; static int y0[4] = {0, 0, 0, 3}; static int firstOffset[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}}; void Move(int dir) { //bool moved = false; if(dir==-1) return; int tx, ty; int t1x, t1y; int t2x, t2y; for(int i=0; i<4; i++) { tx = x0[dir] + i*secondOffset[dir][0]; ty = y0[dir] + i*secondOffset[dir][1]; //cout << "(" << tx << ", " << ty << ")" << endl; t1x = tx; t1y = ty; t2x = tx + firstOffset[dir][0]; t2y = ty + firstOffset[dir][1]; for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1]) { if(grid[t2y][t2x]!=0) { if(grid[t1y][t1x]==0) { grid[t1y][t1x] = grid[t2y][t2x]; grid[t2y][t2x] = 0; // moved = true; } else if(grid[t1y][t1x]==grid[t2y][t2x]) { grid[t1y][t1x]++; grid[t2y][t2x] = 0; t1x += firstOffset[dir][0]; t1y += firstOffset[dir][1]; // moved = true; } else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y) { grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = grid[t2y][t2x]; grid[t2y][t2x] = 0; t1x += firstOffset[dir][0]; t1y += firstOffset[dir][1]; //cout << "Move Test" << endl; // moved = true; } else { t1x += firstOffset[dir][0]; t1y += firstOffset[dir][1]; } } } } //return moved; } //Add new number void addnum(int n) { while(n--)//Add n { EmptyBlock = CalculateEmpty(); if(EmptyBlock<=0) { //cout << "addnum EmptyBlock = " << EmptyBlock << endl; //cout << "addnum Test1" << endl; return; } int cnt = random(EmptyBlock)+1;//Randomly get a number within the number of spaces //Cout < < find the first "< < CNT < < space" < < endl; //cout << "cnt = " << cnt << endl; int *p = &grid[0][0]-1;//Record the first address of the matrix, because the following p will be returned when it is found++ //cout << "n = "<< n <<endl; for(int i=0; i<4&&cnt; i++) for(int j=0; j<4&&cnt; j++) { if(grid[i][j]==0 && cnt)//If there are spaces and cnt is valid { //cout << "cnt = " << cnt << endl; cnt--;//Find one, scratch one } p++;//p points to the next one for judgment } //At the end of the loop, p points to the space we randomly specified before *p = (random(10)==0)?2:1;// The probability of 0.1 is 2 and the probability of 0.9 is 1 //Cout < < insert successfully < < endl; //*p = (random(10)==0)+1;// It's OK to write like this EmptyBlock--; } } int main() { initgraph(200, 200); addnum(2); //Add a new number at 2 random locations ShowInfo(); for ( ; is_run(); delay_fps(60) ) { cleardevice(); // todo: logical update (data update) //Key detection while(kbmsg()) { key_msg keyMsg = getkey(); if(keyMsg.msg == key_msg_down) { switch(keyMsg.key) { case 'A':case key_left : dir = 0; break;//Left case 'W':case key_up : dir = 1; break;//upper case 'D':case key_right : dir = 2; break;//right case 'S':case key_down : dir = 3; break;//lower } } } // todo: drawing updates if(dir!=-1) { system("cls"); switch(dir) { case 0: cout << "Pressed A/Left key" << endl; break;//Left case 1: cout << "Pressed W/Up key" << endl; break;//upper case 2: cout << "Pressed D/Right click" << endl; break;//right case 3: cout << "Pressed S/Down key" << endl; break;//lower } bool flag = false; //Move flag bit int tempGrid[4][4]; //Temporary array int i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) tempGrid[i][j] = grid[i][j]; { //cout << "tempGrid[4][4] = " << endl; // for(i=0; i<4; i++) // { // for(j=0; j<4; j++) // cout << tempGrid[i][j] << " "; // cout << endl; // } // cout << endl; } Move(dir); //compare for(i=0; i<4; i++) for(j=0; j<4; j++) if(grid[i][j]!=tempGrid[i][j]) { flag = true; break; } //If (flag) cout < < move:<< flag << endl; if(flag) { cout << "Effective movement" << endl; addnum(1); } else cout << "Invalid move" << endl; ShowInfo(); dir = -1;//Set dir to invalid, otherwise the console will always refresh } } getch(); closegraph(); return 0; }
4, Operation effect display
Conclusion:
Here, the "kernel" part of the game is almost over. It looks like a 2048, but it's too ugly=
The function implementation is summarized below:
- Mobile logic
- Keyboard input control
- Add new number
The next draft is to write the optimization part (the following tentative points):
- Replace numbers with graphics
- Add scoring
- Class encapsulation