2048game

2048游戏(C语言LINUX环境下,键盘读取实例)

一、Linux键盘值的调用 “get_keyboard.h”

​ 在Linux下是没有自带的调取键盘的库的,所以我们得自己写一个头文件“get_keyborad.h”来获取键盘的值。当然如果在Windows环境下,直接调用“conio.h”头文件中就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// get_keyboard.h在linux下没有直接的get_ch()读取键盘,所以要自己写一个。

#ifndef GETCH_H
#define GETCH_H
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>

typedef enum KEYBOARD
{
KEY_UP = 183,
KEY_DOWN = 184,
KEY_RIGHT = 185,
KEY_LEFT = 186,
KEY_BACKSPACE = 127,
KEY_ENTER = 10,
KEY_0 = 48,
KEY_1 = 49,
KEY_2 = 50,
KEY_3 = 51,
KEY_4 = 52,
KEY_5 = 53,
KEY_6 = 54,
KEY_7 = 55,
KEY_8 = 56,
KEY_9 = 57,
KEY_A = 65,
KEY_B = 66,
KEY_C = 67,
KEY_D = 68,
KEY_E = 69,
KEY_F = 70,
KEY_G = 71,
KEY_H = 72,
KEY_I = 73,
KEY_J = 74,
KEY_K = 75,
KEY_L = 76,
KEY_M = 77,
KEY_N = 78,
KEY_O = 79,
KEY_P = 80,
KEY_Q = 81,
KEY_R = 82,
KEY_S = 83,
KEY_T = 84,
KEY_U = 85,
KEY_V = 86,
KEY_W = 87,
KEY_X = 88,
KEY_Y = 89,
KEY_Z = 90,
KEY_a = 97,
KEY_b = 98,
KEY_c = 99,
KEY_d = 100,
KEY_e = 101,
KEY_f = 102,
KEY_g = 103,
KEY_h = 104,
KEY_i = 105,
KEY_j = 106,
KEY_k = 107,
KEY_l = 108,
KEY_m = 109,
KEY_n = 110,
KEY_o = 111,
KEY_p = 112,
KEY_q = 113,
KEY_r = 114,
KEY_s = 115,
KEY_t = 116,
KEY_u = 117,
KEY_v = 118,
KEY_w = 119,
KEY_x = 120,
KEY_y = 121,
KEY_z = 122
}KEYBOARD;

//此函数能立即从键盘不回显的接收数据
static int get_keyboard(void)
{
//接收系统调用的执行结果
int ret = 0;
//存储终端设备的配置信息
struct termios old;
//通过系统调用获取终端的配置信息
ret=tcgetattr(STDIN_FILENO,&old);
if(0 > ret)
{
perror("tcgetattr");
return -1;
}
//初始化新的终端配置信息
struct termios new = old;
//取消回显并立即获取
new.c_lflag &= ~(ICANON|ECHO);
//设置新的终端配置信息
ret= tcsetattr(STDIN_FILENO,TCSANOW,&new);
if(0 > ret)
{
perror("tcsetattr");
return -2;
}
//在新的模式下从终端获取数据
int key_value = 0;
do
{
key_value += getchar();
//由于和系统对FILE结构体的实现各不相同
//linux系统 while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//OS系统 while(stdin->_r);
}while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//还原终端的配置信息
ret = tcsetattr(STDIN_FILENO,TCSANOW,&old);
if(0 > ret)
{
perror("tcsetattr");
return -3;
}
//返回获取到的数据
return key_value;
}
#endif//GETCH_H

二、代码基本思路

  1. 先初始化加载游戏界面,用二维char类型数组(char map [row1] [col1])来储存交互界面。

  2. 再建一个数值的二维数组(int nmap [row2] [col2])来储存每个格子的数值。

  3. 将数值数组和界面数组建立映射关系,就可以把数值直接反应到交互界面。

  4. 生成随机数,存放到nmap中,刚开始生成3个,之后一次生成一个随机数(2、4、8)。

  5. 方向键的调用与游戏运行的函数设计

    • key = get_keyboard();获取方向值

    • 调用函数判断,对是否能进行移动进行判断。

      • 此处,我采取的是==将每一个方向重新抽离出来==,这样就可以四个方向进行一起判断,再重新写回
      取一列、一行抽离判断
    • 如果能移动,那么是否存在两个相邻或者其中间隔若干个空格的两数相同,如果存在则合并

    • 先合并完成再进行移动。

    • 顺便计算一下得分情况。

    三、源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include"get_keyboard.h" //#include <conio.h> windows下通过这个头文件获取键盘值。

#define MAX_ROW 6 //规格MAX_ROW*MAX_ROW
#define EACH_ROW 3 //每个格子的高度
#define EACH_COL 7 //每个格子的宽度
#define TOTAL_ROW MAX_ROW*(1+EACH_ROW)+1 //总共需要的行数
#define TOTAL_COL MAX_ROW*(1+EACH_COL)+1 //总共需要的列数
#define EACH_TIME_NUM 3 //初始化数字个数<EACH_TIME_NUM

void load();

int multi(int a,int b){ //求指数
int i;
int s = 1;
for(i=0;i<b;i++){
s*=a;
}
return s;
}

void findplace(int *px,int *py,int flag){ //数值和地图位置的映射关系
*px = (flag/MAX_ROW)*(EACH_ROW+1)+EACH_ROW/2+1;
*py = (flag%MAX_ROW)*(EACH_COL+1)+EACH_COL/2+1;
}

void printf_map(char (*map)[]){ //打印游戏地图
int i,j;
char (*board)[TOTAL_COL] = map;
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
printf("%c",board[i][j]);
}
printf("\n");
}
}

int num_len(int num){ //求int的位数
int cnt = 0;
while(num>0){
num/=10;
++cnt;
}
return cnt;
}

int can_arr_move(int arr[]){
int i=0;
int cnt = 0;
for(i=0;i<MAX_ROW;i++){
while(arr[i]==0){
cnt++;
i++;
if(cnt==MAX_ROW) return 0;
}
if(cnt>0 && arr[i]!=0 && i<MAX_ROW){
return 1;
}
if(i<MAX_ROW-1 && arr[i] == arr[i+1] && arr[i]!=0){
return 1;
}
}
return 0;
}

int arr_move(int arr[],int (*nmap)[MAX_ROW],int *pscore){
int i;
int p;
int n=0;
int temp;
for(i=0;i<MAX_ROW;i++){
while(i<MAX_ROW-1 && arr[i]==0){//找到首非零元素
i++;
}
if(i == MAX_ROW-1) break;
p = i+1;
while(p<MAX_ROW && arr[p]==0) ++p;//找下一个非零元素的位置
if(p==MAX_ROW) break;
if(arr[p]==arr[i]){//如果两数相等则合并
arr[i] = arr[i]*2;
*pscore += arr[i];
arr[p] = 0;
i = p;
}
}
//合并完成后,开始移动位置
for(i=1;i<MAX_ROW;i++){
temp = i;
while(arr[temp-1]==0&&temp>0){
arr[temp-1] = arr[temp];
arr[temp] = 0;
--temp;
}
}
}

int can_move(int (*nmap)[MAX_ROW],int dirc,int mod,int *pscore){
int i,j;
int x,y;
int arr[MAX_ROW]={0};
int res = 0;
int cnt=0;
// 把所有序列转存到新的数组arr
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
arr[j] = nmap[j][i];
break;
case KEY_DOWN:
arr[j] = nmap[MAX_ROW-j-1][i];
break;
case KEY_LEFT:
arr[j] = nmap[i][j];
break;
case KEY_RIGHT:
arr[j] = nmap[i][MAX_ROW-j-1];
break;
}
}
res = can_arr_move(arr);
if(mod && res) return 1;
cnt += res;
// 如果可以移动,反向存回nmap(4*4数字表)
if(res){
arr_move(arr,nmap,pscore);
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
nmap[j][i] = arr[j];
break;
case KEY_DOWN:
nmap[MAX_ROW-j-1][i] = arr[j];
break;
case KEY_LEFT:
nmap[i][j] = arr[j];
break;
case KEY_RIGHT:
nmap[i][MAX_ROW-j-1] = arr[j];
break;
}
}
}
}
return cnt;
}

int move(char (*map)[TOTAL_COL],int (*nmap)[MAX_ROW],int dirc,int *pscore){ //运动
int i,j,k;
int cnt0=0;//记录0的个数
int x=0,y=0;
int nlen=0;
int m2;
if(can_move(nmap,dirc,0,pscore)){
srand((unsigned)time(NULL));
int a = rand()%3+1;
m2 = multi(2,a); //2^1~2^3
int p = rand()%(MAX_ROW*MAX_ROW);
while(nmap[p/MAX_ROW][p%MAX_ROW]!=0){
p = rand()%(MAX_ROW*MAX_ROW);
}
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
//将nmap 4*4的int数组 映射到map里。
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
findplace(&x,&y,i*MAX_ROW+j);
nlen = num_len(nmap[i][j]);
for(k=0;k<EACH_COL-2;k++){
map[x][y-EACH_COL/2+k] = ' ';//每次清空上次数据
}
if(nmap[i][j]!=0){
for(k=0;k<nlen;k++){
map[x][y-nlen/2+k] = nmap[i][j]/multi(10,nlen-k-1)%10+'0';//以字符的形式传入
}
}
}
}
}
for(i=0;i<MAX_ROW*MAX_ROW;i++){
if(nmap[i/MAX_ROW][i%MAX_ROW]==0){
++cnt0;
break;
}
}

printf(" SCORE: %d\n",*pscore);
printf_map(map);
if(cnt0==0 && can_move(nmap,KEY_UP,1,pscore)==0 && can_move(nmap,KEY_LEFT,1,pscore)==0){
return -1;
}
}


void play(char (*map)[],int (*nmap)[],int *pscore){
int key;
int r=0;
while(1){
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
switch(key){
case KEY_UP:
case KEY_DOWN:
case KEY_LEFT:
case KEY_RIGHT:
system("clear"); //windows system("cls")
r = move(map,nmap,key,pscore);
break;
case KEY_R:
case KEY_r:
system("clear"); //windows system("cls")
load();
break;
case KEY_Q:
case KEY_q: exit(0);
}
if(r==-1) {
printf("Game over ~\n");
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
if(key == KEY_R || key == KEY_r) load();
else exit(0);
}
}
}

void load(){
int i,j;
int m,p;
int m2;
int score = 0;
char map[TOTAL_ROW][TOTAL_COL];
system("clear"); //windows system("cls")
printf("小游戏1024\n");
printf("press 'r' to restart , press 'q' to quit.");
printf("\nAre you ready? Press any key to start ...\n");
get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
system("clear"); //windows system("cls")
printf(" SCORE: %d\n",score);
//初始化 游戏界面设计
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
if(i%(1+EACH_ROW)==0||i==TOTAL_ROW-1){
map[i][j] = '-';
}
else{
if(j%(1+EACH_COL)==0||j==TOTAL_COL-1){
map[i][j] = '|';
}
else{
map[i][j] = ' ';
}
}
}
}
//初始化值
srand((unsigned)time(NULL));
int x=0;
int y=0;
int nmap[MAX_ROW][MAX_ROW] = {0};
for(i=0;i<EACH_TIME_NUM;i++){
m = rand()%3+1;
m2 = multi(2,m);
p = rand()%16;
findplace(&x,&y,p);
map[x][y] = m2+'0';
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
}
printf_map(map);
play(map,nmap,&score);
}

int main(){
load();
return 0;
}

2048游戏(C语言LINUX环境下,键盘读取实例)

2048游戏(C语言LINUX环境下,键盘读取实例)

一、Linux键盘值的调用 “get_keyboard.h”

​ 在Linux下是没有自带的调取键盘的库的,所以我们得自己写一个头文件“get_keyborad.h”来获取键盘的值。当然如果在Windows环境下,直接调用“conio.h”头文件中就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// get_keyboard.h在linux下没有直接的get_ch()读取键盘,所以要自己写一个。

#ifndef GETCH_H
#define GETCH_H
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>

typedef enum KEYBOARD
{
KEY_UP = 183,
KEY_DOWN = 184,
KEY_RIGHT = 185,
KEY_LEFT = 186,
KEY_BACKSPACE = 127,
KEY_ENTER = 10,
KEY_0 = 48,
KEY_1 = 49,
KEY_2 = 50,
KEY_3 = 51,
KEY_4 = 52,
KEY_5 = 53,
KEY_6 = 54,
KEY_7 = 55,
KEY_8 = 56,
KEY_9 = 57,
KEY_A = 65,
KEY_B = 66,
KEY_C = 67,
KEY_D = 68,
KEY_E = 69,
KEY_F = 70,
KEY_G = 71,
KEY_H = 72,
KEY_I = 73,
KEY_J = 74,
KEY_K = 75,
KEY_L = 76,
KEY_M = 77,
KEY_N = 78,
KEY_O = 79,
KEY_P = 80,
KEY_Q = 81,
KEY_R = 82,
KEY_S = 83,
KEY_T = 84,
KEY_U = 85,
KEY_V = 86,
KEY_W = 87,
KEY_X = 88,
KEY_Y = 89,
KEY_Z = 90,
KEY_a = 97,
KEY_b = 98,
KEY_c = 99,
KEY_d = 100,
KEY_e = 101,
KEY_f = 102,
KEY_g = 103,
KEY_h = 104,
KEY_i = 105,
KEY_j = 106,
KEY_k = 107,
KEY_l = 108,
KEY_m = 109,
KEY_n = 110,
KEY_o = 111,
KEY_p = 112,
KEY_q = 113,
KEY_r = 114,
KEY_s = 115,
KEY_t = 116,
KEY_u = 117,
KEY_v = 118,
KEY_w = 119,
KEY_x = 120,
KEY_y = 121,
KEY_z = 122
}KEYBOARD;

//此函数能立即从键盘不回显的接收数据
static int get_keyboard(void)
{
//接收系统调用的执行结果
int ret = 0;
//存储终端设备的配置信息
struct termios old;
//通过系统调用获取终端的配置信息
ret=tcgetattr(STDIN_FILENO,&old);
if(0 > ret)
{
perror("tcgetattr");
return -1;
}
//初始化新的终端配置信息
struct termios new = old;
//取消回显并立即获取
new.c_lflag &= ~(ICANON|ECHO);
//设置新的终端配置信息
ret= tcsetattr(STDIN_FILENO,TCSANOW,&new);
if(0 > ret)
{
perror("tcsetattr");
return -2;
}
//在新的模式下从终端获取数据
int key_value = 0;
do
{
key_value += getchar();
//由于和系统对FILE结构体的实现各不相同
//linux系统 while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//OS系统 while(stdin->_r);
}while(stdin->_IO_read_end - stdin->_IO_read_ptr);
//还原终端的配置信息
ret = tcsetattr(STDIN_FILENO,TCSANOW,&old);
if(0 > ret)
{
perror("tcsetattr");
return -3;
}
//返回获取到的数据
return key_value;
}
#endif//GETCH_H

二、代码基本思路

  1. 先初始化加载游戏界面,用二维char类型数组(char map [row1] [col1])来储存交互界面。

  2. 再建一个数值的二维数组(int nmap [row2] [col2])来储存每个格子的数值。

  3. 将数值数组和界面数组建立映射关系,就可以把数值直接反应到交互界面。

  4. 生成随机数,存放到nmap中,刚开始生成3个,之后一次生成一个随机数(2、4、8)。

  5. 方向键的调用与游戏运行的函数设计

    • key = get_keyboard();获取方向值

    • 调用函数判断,对是否能进行移动进行判断。

      • 此处,我采取的是==将每一个方向重新抽离出来==,这样就可以四个方向进行一起判断,再重新写回
      取一列、一行抽离判断
    • 如果能移动,那么是否存在两个相邻或者其中间隔若干个空格的两数相同,如果存在则合并

    • 先合并完成再进行移动。

    • 顺便计算一下得分情况。

    三、源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include"get_keyboard.h" //#include <conio.h> windows下通过这个头文件获取键盘值。

#define MAX_ROW 6 //规格MAX_ROW*MAX_ROW
#define EACH_ROW 3 //每个格子的高度
#define EACH_COL 7 //每个格子的宽度
#define TOTAL_ROW MAX_ROW*(1+EACH_ROW)+1 //总共需要的行数
#define TOTAL_COL MAX_ROW*(1+EACH_COL)+1 //总共需要的列数
#define EACH_TIME_NUM 3 //初始化数字个数<EACH_TIME_NUM

void load();

int multi(int a,int b){ //求指数
int i;
int s = 1;
for(i=0;i<b;i++){
s*=a;
}
return s;
}

void findplace(int *px,int *py,int flag){ //数值和地图位置的映射关系
*px = (flag/MAX_ROW)*(EACH_ROW+1)+EACH_ROW/2+1;
*py = (flag%MAX_ROW)*(EACH_COL+1)+EACH_COL/2+1;
}

void printf_map(char (*map)[]){ //打印游戏地图
int i,j;
char (*board)[TOTAL_COL] = map;
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
printf("%c",board[i][j]);
}
printf("\n");
}
}

int num_len(int num){ //求int的位数
int cnt = 0;
while(num>0){
num/=10;
++cnt;
}
return cnt;
}

int can_arr_move(int arr[]){
int i=0;
int cnt = 0;
for(i=0;i<MAX_ROW;i++){
while(arr[i]==0){
cnt++;
i++;
if(cnt==MAX_ROW) return 0;
}
if(cnt>0 && arr[i]!=0 && i<MAX_ROW){
return 1;
}
if(i<MAX_ROW-1 && arr[i] == arr[i+1] && arr[i]!=0){
return 1;
}
}
return 0;
}

int arr_move(int arr[],int (*nmap)[MAX_ROW],int *pscore){
int i;
int p;
int n=0;
int temp;
for(i=0;i<MAX_ROW;i++){
while(i<MAX_ROW-1 && arr[i]==0){//找到首非零元素
i++;
}
if(i == MAX_ROW-1) break;
p = i+1;
while(p<MAX_ROW && arr[p]==0) ++p;//找下一个非零元素的位置
if(p==MAX_ROW) break;
if(arr[p]==arr[i]){//如果两数相等则合并
arr[i] = arr[i]*2;
*pscore += arr[i];
arr[p] = 0;
i = p;
}
}
//合并完成后,开始移动位置
for(i=1;i<MAX_ROW;i++){
temp = i;
while(arr[temp-1]==0&&temp>0){
arr[temp-1] = arr[temp];
arr[temp] = 0;
--temp;
}
}
}

int can_move(int (*nmap)[MAX_ROW],int dirc,int mod,int *pscore){
int i,j;
int x,y;
int arr[MAX_ROW]={0};
int res = 0;
int cnt=0;
// 把所有序列转存到新的数组arr
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
arr[j] = nmap[j][i];
break;
case KEY_DOWN:
arr[j] = nmap[MAX_ROW-j-1][i];
break;
case KEY_LEFT:
arr[j] = nmap[i][j];
break;
case KEY_RIGHT:
arr[j] = nmap[i][MAX_ROW-j-1];
break;
}
}
res = can_arr_move(arr);
if(mod && res) return 1;
cnt += res;
// 如果可以移动,反向存回nmap(4*4数字表)
if(res){
arr_move(arr,nmap,pscore);
for(j=0;j<MAX_ROW;j++){
switch(dirc){
case KEY_UP:
nmap[j][i] = arr[j];
break;
case KEY_DOWN:
nmap[MAX_ROW-j-1][i] = arr[j];
break;
case KEY_LEFT:
nmap[i][j] = arr[j];
break;
case KEY_RIGHT:
nmap[i][MAX_ROW-j-1] = arr[j];
break;
}
}
}
}
return cnt;
}

int move(char (*map)[TOTAL_COL],int (*nmap)[MAX_ROW],int dirc,int *pscore){ //运动
int i,j,k;
int cnt0=0;//记录0的个数
int x=0,y=0;
int nlen=0;
int m2;
if(can_move(nmap,dirc,0,pscore)){
srand((unsigned)time(NULL));
int a = rand()%3+1;
m2 = multi(2,a); //2^1~2^3
int p = rand()%(MAX_ROW*MAX_ROW);
while(nmap[p/MAX_ROW][p%MAX_ROW]!=0){
p = rand()%(MAX_ROW*MAX_ROW);
}
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
//将nmap 4*4的int数组 映射到map里。
for(i=0;i<MAX_ROW;i++){
for(j=0;j<MAX_ROW;j++){
findplace(&x,&y,i*MAX_ROW+j);
nlen = num_len(nmap[i][j]);
for(k=0;k<EACH_COL-2;k++){
map[x][y-EACH_COL/2+k] = ' ';//每次清空上次数据
}
if(nmap[i][j]!=0){
for(k=0;k<nlen;k++){
map[x][y-nlen/2+k] = nmap[i][j]/multi(10,nlen-k-1)%10+'0';//以字符的形式传入
}
}
}
}
}
for(i=0;i<MAX_ROW*MAX_ROW;i++){
if(nmap[i/MAX_ROW][i%MAX_ROW]==0){
++cnt0;
break;
}
}

printf(" SCORE: %d\n",*pscore);
printf_map(map);
if(cnt0==0 && can_move(nmap,KEY_UP,1,pscore)==0 && can_move(nmap,KEY_LEFT,1,pscore)==0){
return -1;
}
}


void play(char (*map)[],int (*nmap)[],int *pscore){
int key;
int r=0;
while(1){
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
switch(key){
case KEY_UP:
case KEY_DOWN:
case KEY_LEFT:
case KEY_RIGHT:
system("clear"); //windows system("cls")
r = move(map,nmap,key,pscore);
break;
case KEY_R:
case KEY_r:
system("clear"); //windows system("cls")
load();
break;
case KEY_Q:
case KEY_q: exit(0);
}
if(r==-1) {
printf("Game over ~\n");
key = get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
if(key == KEY_R || key == KEY_r) load();
else exit(0);
}
}
}

void load(){
int i,j;
int m,p;
int m2;
int score = 0;
char map[TOTAL_ROW][TOTAL_COL];
system("clear"); //windows system("cls")
printf("小游戏1024\n");
printf("press 'r' to restart , press 'q' to quit.");
printf("\nAre you ready? Press any key to start ...\n");
get_keyboard(); //windows 用getch() ->别忘了头文件 #include<conio.h>
system("clear"); //windows system("cls")
printf(" SCORE: %d\n",score);
//初始化 游戏界面设计
for(i=0;i<TOTAL_ROW;i++){
for(j=0;j<TOTAL_COL;j++){
if(i%(1+EACH_ROW)==0||i==TOTAL_ROW-1){
map[i][j] = '-';
}
else{
if(j%(1+EACH_COL)==0||j==TOTAL_COL-1){
map[i][j] = '|';
}
else{
map[i][j] = ' ';
}
}
}
}
//初始化值
srand((unsigned)time(NULL));
int x=0;
int y=0;
int nmap[MAX_ROW][MAX_ROW] = {0};
for(i=0;i<EACH_TIME_NUM;i++){
m = rand()%3+1;
m2 = multi(2,m);
p = rand()%16;
findplace(&x,&y,p);
map[x][y] = m2+'0';
nmap[p/MAX_ROW][p%MAX_ROW] = m2;
}
printf_map(map);
play(map,nmap,&score);
}

int main(){
load();
return 0;
}