# 2048 - third draft of specific function realization [add new number]

Keywords: C++ Game Development

2048 game - Implementation of specific functions third draft [add new number]

(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

1. 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 = {
{0,1,2,3},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
```
2. 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

1. If EmptyBlock = 0, there is no vacancy
2. Using the random function of EGE
```random(n);//Returns an integer from 0 to n-1
```

Suppose the grid is as follows:

```int grid = {
{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
{
{
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-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

1. Matrix set to 0

```int grid = {0};//Matrix set to 0
```
2. ShowInfo() print information function

```//Display information - centralize some information to be printed
void ShowInfo()
{
cout << "dir = " << dir << endl;
cout<< "EmptyBlock = " << CalculateEmpty() << endl;
PrintGrid();
}
```
3. Judge whether the movement is effective (the first idea used)

``` 			bool flag = false;    //Move flag bit
int tempGrid;	 //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 = " << 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)
{
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 = {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 = " << endl;
PrintGrid();
}

//Moving function
static int x0 = {0, 0, 3, 0};
static int y0 = {0, 0, 0, 3};
static int firstOffset  = {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset = {{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];
ty = y0[dir] + i*secondOffset[dir];
//cout << "(" << tx << ", " << ty << ")" << endl;

t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir];
t2y = ty + firstOffset[dir];
for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir],t2y+=firstOffset[dir])
{
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];
t1y += firstOffset[dir];
// moved = true;
}
else if(t1x+firstOffset[dir]!=t2x||t1y+firstOffset[dir]!=t2y)
{
grid[t1y+firstOffset[dir]][t1x+firstOffset[dir]] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
t1x += firstOffset[dir];
t1y += firstOffset[dir];
//cout << "Move Test" << endl;
// moved = true;
}
else
{
t1x += firstOffset[dir];
t1y += firstOffset[dir];
}
}

}
}
//return moved;
}

{
{
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-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);
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
}
}
}
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;	 //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 = " << 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;
}
else	cout << "Invalid move" << endl;
ShowInfo();
dir = -1;//Set dir to invalid, otherwise the console will always refresh
}
}
getch();
closegraph();
return 0;
}
```

# 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:

1. Mobile logic
2. Keyboard input control 