头文件
#ifndef __COMMON_H
#define __COMMON_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MATRIX_X0 0 //整个棋盘的左上角顶点的x轴坐标
#define MATRIX_Y0 0 //整个棋盘的左上角顶点的y轴坐标
#define BOARDSIZE 4 // 整个棋盘的大小BORADSIZE * BOARDSIZE
#define MOVE_LEFT 1
#define MOVE_RIGHT 2
#define MOVE_UP 3
#define MOVE_DOWN 4
extern int g_lcd_width;
extern int g_lcd_height;
extern int g_lcd_bpp;
//游戏结束标志
bool game_over = false;
int *plcd = NULL;//指向framebuffer(屏幕显存第一个点的内存)
//将所有的图片名保存到一个数组中
const char * bmpfiles[] =
{
"res/2.bmp",
"res/4.bmp",
"res/8.bmp",
"res/16.bmp",
"res/32.bmp",
"res/64.bmp",
"res/128.bmp",
"res/256.bmp",
"res/512.bmp",
"res/1024.bmp",
"res/2048.bmp",
"res/4096.bmp",
"res/8192.bmp",
"res/16384.bmp",
"res/32768.bmp",
"res/65536.bmp",
};
#endif
文件名bmp.h
#ifndef __BMP_H
#define __BMP_H
struct header
{
int16_t type;
int32_t size;
int16_t reserved1;
int16_t reserved2;
int32_t offbytes;
}__attribute__((packed));
struct info
{
int32_t size;
int32_t width;
int32_t height;
int16_t planes;
int16_t bit_count;
int32_t compression;
int32_t size_img;
int32_t xpel;
int32_t ypel;
int32_t clrused;
int32_t partant;
}__attribute__((packed));
#endif
2048.c
#include "common.h"
#include "bmp.h"
int g_lcd_width = 0;
int g_lcd_height = 0;
int g_lcd_bpp = 0;
/*
get_bmpfiles_index:根据你要显示的数字(2,4,8,16,...)
返回你对应的文件名的下标
返回值:
返回 x对应的文件名在数组bmpfiles的下标
*/
int get_bmpfiles_index(int x)
{
int exp;
for(exp=0; x!=0; x >>= 1, exp++);
return exp-2;
}
//棋盘矩阵
int matrix[BOARDSIZE][BOARDSIZE] =
{
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0
};
/*
get_zero_num:求棋盘矩阵里面有多少个0
返回值:
返回棋盘矩阵中0的个数
*/
int get_zero_num(void)
{
int z = 0;//棋盘矩阵中元素为0的个数
int i, j;
//BOARDSIZE = 4,整个棋盘大小为BOARDSIZE*BOARDSIZE
for (i = 0; i < BOARDSIZE; i++)
{
for (j = 0; j < BOARDSIZE; j++)
{
if (matrix[i][j] == 0)
{
z++;
}
}
}
return z;
}
/*
set_matrix:给棋盘矩阵第z个0的位置,填充一个
值s
*/
void set_matrix(int z, int s)
{
int i, j;
int k = 0 ;//0的个数
for (i = 0; i < BOARDSIZE ;i++)
{
for (j = 0; j < BOARDSIZE; j++)
{
if (matrix[i][j] == 0)
{
k++;
if (k == z)
{
matrix[i][j] = s;
return ;
}
}
}
}
}
/*
lcd_draw_point:在屏幕坐为(x, y)这个点,填充color
这个颜色值。
@x: x轴坐标
@y: y轴坐标
@color: 要填充的辨色值
返回值:
无返回值。
*/
void lcd_draw_point(int x, int y, int color)
{
int *p = plcd;
if (x >= 0 && x < g_lcd_width && y>=0 && y < g_lcd_height)
{
*(p + g_lcd_width *y + x) = color;
}
}
/*
lcd_draw_dect: 在屏幕上画一个矩形,并且用
color这种颜色填充该矩形。
@x0:该矩形的左上角的那个点x轴坐标
@y0:该矩形的左上角的那个点y轴坐标
@w:该矩形的宽
@h:该矩形的高
@color:该矩形要填充的色值
返回值:
无返回值。
*/
void lcd_draw_dect(int x0, int y0, int w, int h, int color)
{
if (x0 < 0 || y0 < 0 || w < 0 || h <0)
return;
if ((x0 + w > g_lcd_width) || (y0+h) > g_lcd_height)
{
return;
}
int x, y;
for (y = y0; y < y0 + h; y++)
{
for (x = x0; x < x0 + w; x++)
{
lcd_draw_point(x, y, color);
}
}
}
/*
draw_bmp:把一张bmp图片显示在屏幕上特定的位置
@bmpfile:要显示的bmp图片的文件名
@x0: 在屏幕上显示的左上角顶点的x轴坐标
@y0: 在屏幕上显示的左上角顶点的y轴坐标
返回值:
无返回值.
*/
void draw_bmp(const char *bmpfile, int x0, int y0)
{
int fd;
int x, y;
fd = open(bmpfile, O_RDONLY);
if (fd == -1)
{
perror("open bmpfile error:");
return ;
}
struct header head;
struct info info;
read(fd, &head, sizeof(head));
read(fd, &info, sizeof(info));
char *bmpdata = calloc(1, head.size-head.offbytes);
read(fd, bmpdata, info.width * info.height * info.bit_count/8);
close(fd);
int i = 0;
for (y = 0; y < info.height; y++)
{
unsigned char r,g ,b;
int color;
for (x = 0; x < info.width; x++)
{
b = bmpdata[i++];
g = bmpdata[i++];
r = bmpdata[i++];
color = (r << 16) | (g << 8) | b;
lcd_draw_point(x0+ x, y0 + (info.height -1 - y) ,color);
}
}
free(bmpdata);
}
/*
draw_matrix:把棋盘矩阵在屏幕上显示出来
*/
void draw_matrix(void)
{
int i, j;
for (i = 0; i < BOARDSIZE; i++)
{
for (j = 0; j < BOARDSIZE;j++)
{
int x0, y0;
x0 = 185;//棋盘矩阵左上角那个点的x轴坐标
y0 = 25;//棋盘矩阵左上角那个点的y轴坐标
if (matrix[i][j] == 0)
{
lcd_draw_dect(x0+j*110, y0+i*110,
100 , 100,
0xb4eeb4);//如果此处元素的值为0,那么
//就显示
}
else
{
int f_index = get_bmpfiles_index(matrix[i][j]);
draw_bmp(bmpfiles[f_index],
x0+j*110, y0+i*110);
}
}
}
}
/*
init_matrix:初始化棋盘矩阵
在任意x个位置,填充x个数字(2,4,8)
*/
void init_matrix(void)
{
//规则x >= 1,x <= 3
int x = (random() % 3) + 1;
int i;
/*
step1:随机产生x个数字,并填充到棋盘矩阵中去
*/
for(i = 0; i < x; i++)
{
int pos = (random() % get_zero_num()) + 1;
int s[] = {2, 4, 8, 2};
int s_i = (random() % 3);
set_matrix(pos, s[s_i]);
}
/*
step 2: 绘制棋盘矩阵
*/
draw_matrix();
}
/*
rand1_matrix:移动之后随机产生一个数字填充到
任意一个0的位置上
*/
void rand_matrix()
{
int pos = (random() % get_zero_num()) + 1;
int s[] = {2, 4, 8, 2};
int s_i = (random() % 4);
set_matrix(pos, s[s_i]);
draw_matrix();
}
/*
get_finger_direction:获取手指在触摸屏上面的滑动方向
返回值:
MOVE_LEFT:手指向左移动
MOVE_RIGHT:手指向右移动
MOVE_UP:手指向上移动
MOVE_DOWN:手指向下移动
*/
int get_finger_direction()
{
int ret;
int fd = open("/dev/input/event0", O_RDONLY);
if (fd == -1)
{
perror("open event failed:");
return -1;
}
struct input_event ev;
int x1 = -1; //在滑动过程中第一个点的x轴坐标
int x2; //在滑动过程中最后一个点的x轴坐标
int y1 = -1;//在滑动过程中第一个点的y轴坐标
int y2;//在滑动过程中最后一个点的y轴坐标
while (1)
{
ret = read(fd, &ev, sizeof(ev));
if(ret != sizeof(ev))
{
continue;
}
if (ev.type == EV_ABS && ev.code == ABS_X)//是x轴坐标
{
if (x1 == -1)//x1重来没有赋过值,那么肯定是第一个点
{
x1 = ev.value;
}
x2 = ev.value;
}
if (ev.type == EV_ABS && ev.code == ABS_Y)//是y轴坐标
{
if ( y1 == -1)//y1重来没有赋过值,那么肯定是第一个点
{
y1 = ev.value;
}
y2 = ev.value;
}
if (ev.type == EV_KEY && ev.code == BTN_TOUCH //手指弹起,再计算滑动方向
&& ev.value == 0)//触摸屏压力值为0, press up
{
int x_cz;//x轴的位移
int y_cz;//y轴的位移
int abs_x;
int abs_y;
x_cz = x2 - x1;
y_cz = y2 - y1;
abs_x = abs(x_cz);
abs_y = abs(y_cz);
if((x_cz > 30) && (abs_x > 2 * abs_y))
{
close(fd);
return MOVE_RIGHT;
}
else if((x_cz < -30) && (abs_x > 2 * abs_y))
{
close(fd);
return MOVE_LEFT;
}
else if((y_cz > 30) && (abs_y > 2 * abs_x))
{
close(fd);
return MOVE_UP;
}
else if((y_cz < -30) && (abs_y > 2 * abs_x))
{
close(fd);
return MOVE_DOWN;
}
else
{
x1 = y1 = -1;
continue;
}
}
}
close(fd);
}
/*
fin_left:手指左划后棋子移动及合并的方式
*/
void fin_left()
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value, save_zero;
for(i = 0; i < BOARDSIZE; i++)
{
value = 0;
save_zero= 0;
for(j = 0; j < BOARDSIZE ; j++)
{
if (matrix[i][j] == 0)
continue;
if (value == 0)
value = matrix[i][j];
else
{
if (value == matrix[i][j])
{
matrix[i][save_zero++] = value * 2;
value = 0;
} else {
matrix[i][save_zero++] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if (value != 0)
matrix[i][save_zero] = value;
}
}
/*
手指上划后棋子移动及合并的方式
*/
void fin_right()
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for (i = 0; i < BOARDSIZE; i++)
{
value = 0;
save_zero = BOARDSIZE -1;
for (j = BOARDSIZE - 1; j >= 0 ; j--)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[i][save_zero--] = 2 * value;
value = 0;
}
else
{
matrix[i][save_zero--] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[i][save_zero] = value;
}
}
}
/*
fin_up:手指上划后棋子移动及合并的方式
*/
void fin_up()
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for(j = 0; j < BOARDSIZE; j++)
{
value = 0;
save_zero= 0;
for(i = 0; i < BOARDSIZE ; i++)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[save_zero++][j] =2 * value;
value = 0;
}
else
{
matrix[save_zero++][j] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[save_zero][j] = value;
}
}
}
//draw_matrix();
/*
fin_down:手指上划后棋子移动及合并的方式
*/
void fin_down()
{
int i, j;//i为矩阵行下标,j为矩阵列下标
int value;
int save_zero;
for(j = 0; j < BOARDSIZE; j++)
{
value = 0;
save_zero = BOARDSIZE - 1;
for(i = BOARDSIZE - 1; i >= 0 ; i--)
{
if(matrix[i][j] == 0)
{
continue;
}
if(value == 0)
{
value = matrix[i][j];
}
else
{
if(value == matrix[i][j])
{
matrix[save_zero--][j] = 2 * value;
value = 0;
}
else
{
matrix[save_zero--][j] = value;
value = matrix[i][j];
}
}
matrix[i][j] = 0;
}
if(value != 0)
{
matrix[save_zero][j] = value;
}
}
}
/*
判断是否还能移动
*/
bool is_game_over(void)
{
int i, j;
if(get_zero_num() != 0)
{
return false;
}
for(i = 0; i < BOARDSIZE; i++)
{
for(j = 0; j < BOARDSIZE ; j++)
{
if (j != BOARDSIZE -1)
{
if (matrix[i][j] == matrix[i][j+1])
{
return false;
}
}
if (i != BOARDSIZE - 1)
{
if (matrix[i][j] == matrix[i+1][j])
{
return false;
}
}
}
}
return true;
}
/*
change_matrix:根据手指滑动(direction),
变换棋盘矩阵
*/
int change_matrix()
{
int direction = get_finger_direction();
if (direction == MOVE_LEFT)
{
fin_left();
}
else if (direction == MOVE_RIGHT)
{
fin_right();
}
else if (direction == MOVE_UP)
{
fin_down();
}
else
{
fin_up();
}
}
int main(void)
{
int lcd = open("/dev/fb0", O_RDWR);
if (lcd == -1)
{
perror("open fb0 failed:");
exit(0);
}
struct fb_var_screeninfo vinfo;
ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);
g_lcd_width = vinfo.xres;
g_lcd_height = vinfo.yres;
g_lcd_bpp = vinfo.bits_per_pixel;
int screen_size = g_lcd_width * g_lcd_height * g_lcd_bpp/8;
plcd = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, lcd, 0);
lcd_draw_dect(0, 0, g_lcd_width, g_lcd_height, 0xffffff);//清屏
srandom(time(NULL)); //设置随机数种子
init_matrix();
while (!game_over) //游戏没结束
{
//用来保存原来的矩阵值
int matrix_v1[BOARDSIZE][BOARDSIZE];
int i, j, flag = 0;
for(i = 0; i < BOARDSIZE; ++i)
{
for (j = 0; j < BOARDSIZE; ++j)
{
matrix_v1[i][j] = matrix[i][j];
}
}
/*
step 1: 变换矩阵
*/
change_matrix();
for (i = 0; i < BOARDSIZE; ++i)
{
for (j = 0; j < BOARDSIZE; ++j)
{
if (matrix_v1[i][j] != matrix[i][j])
{
flag = 1;
i = j = BOARDSIZE;
}
}
}
if (flag)
{
rand_matrix();
draw_matrix();
}
else
{
draw_matrix();
}
game_over = is_game_over();
}
lcd_draw_dect(0, 0, g_lcd_width, g_lcd_height, 0xffffff);//清屏
draw_bmp("res/game_over.bmp", 250, 165);
munmap(plcd, screen_size);
close(lcd);
}