#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
//#include <unistd.h>
//#include <sys/types.h>
//#include <stropts.h>
//#include <sys/select.h>
/*"▣" "▣" "▊" "■" */
#define NONE "\33[m"
#define RED "\33[0;32;31m"
#define LIGHT_RED "\33[1;31m"
#define GREEN "\33[0;32;32m"
#define LIGHT_GREEN "\33[1;32m"
#define BLUE "\33[0;32;34m"
#define LIGHT_BLUE "\33[1;34m"
#define DARY_GRAY "\33[1;30m"
#define CYAN "\33[0;36m"
#define LIGHT_CYAN "\33[1;36m"
#define PURPLE "\33[0;35m"
#define LIGHT_PURPLE "\33[1;35m"
#define BROWN "\33[0;33m"
#define YELLOW "\33[1;33m"
#define LIGHT_GRAY "\33[0;37m"
#define WHITE "\33[1;37m"
#define ENTER "\n"
// 清除屏幕
#define CLEAR() printf("\33[2J")
//清除从光标位置到行末的内容
#define CLEAR_TAIL() printf("\33[K");
// 上移光标
#define MOVE_UP(x) printf("\33[%dA", (x))
// 下移光标
#define MOVE_DOWN(x) printf("\33[%dB", (x))
// 左移光标
#define MOVE_LEFT(y) printf("\33[%dD", (y))
// 右移光标
#define MOVE_RIGHT(y) printf("\33[%dC",(y))
// 定位光标
#define MOVETO(x,y) printf("\33[%d;%dH", (x), (y))
// 光标复位
#define RESET_CURSOR() printf("\33[H")
// 隐藏光标
#define HIDE_CURSOR() printf("\33[?25l")
// 显示光标
#define SHOW_CURSOR() printf("\33[?25h")
//反显
#define HIGHT_LIGHT() printf("\33[7m")
#define UN_HIGHT_LIGHT() printf("\33[27m")
#define STDIN 0
#define NUM_MAX_KEY 25
#define TIME_SLEEP (500 * 1000) //ms
#define NUM_MAX_Y 20
#define NUM_MAX_X 10
#define NUM_BOX 4
#define CHAR_A 'a'
#define CHAR_D 'd'
#define CHAR_S 's'
#define CHAR_Q 'q'
#define CHAR_SPACE ' '
#define CHAR_LEFT 0x44
#define CHAR_RIGHT 0x43
#define CHAR_DOWN 0x42
#define STR_BOX "▣"
#define STR_FRAME_X "-"
#define STR_FRAME_Y "|"
#define STR_POINT "."
typedef struct t_box
{
int x;
int y;
}t_box; //坐标
static t_box box[NUM_BOX];
static int s_score;
static struct termios st_tr_save;
static char s_buf_point[NUM_MAX_Y][NUM_MAX_X];
static void termios_init()
{
struct termios tmp;
tcgetattr(STDIN, &st_tr_save);
tmp=st_tr_save;
tmp.c_lflag &= ~ECHO;
tmp.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &tmp);
}
static void termios_recover()
{
tcsetattr(STDIN, TCSANOW, &st_tr_save);
}
static int get_key(char *key, int *num_key)
{
int ret, num, i, cnt = 0;
fd_set fds;
struct timeval tv;
char buf[NUM_MAX_KEY] = {0};
*num_key = 0;
FD_ZERO(&fds);
FD_SET(STDIN, &fds); //文件描述符0表示STDIN键盘输入
tv.tv_sec = 0;
tv.tv_usec = TIME_SLEEP;
ret = select(STDIN + 1, &fds, NULL, NULL, &tv); //第一个参数是监控句柄号+1
if(0 >= ret)
return ret;
if(!FD_ISSET(STDIN, &fds)) //监控输入的确是已经发生了改变
return ret;
num = read(STDIN, buf, NUM_MAX_KEY); //从键盘读取输入
for (i = 0; i < num; i++) { /* a s d 空格 */
if ((CHAR_A == buf[i]) || (CHAR_S == buf[i]) || (CHAR_D == buf[i]) || (CHAR_SPACE == buf[i]) || (CHAR_Q == buf[i]))
key[cnt++] = buf[i];
/*0x1b5b 方向键控制符,thinkpad是 0x5b 0x1b5b41 up(完整键值) 42 down 43 right 44 left*/
else if (0x5b == buf[i]) {
if ((CHAR_DOWN <= buf[i + 1]) && (CHAR_LEFT >= buf[i + 1]))
key[cnt++] = buf[++i];
}
}
*num_key = cnt;
return ret;
}
static int deal_score()
{
int i, j, flg;
for (i = 0; i < NUM_MAX_Y; i++) {
flg = 1;
for (j = 0; j < NUM_MAX_X; j++) {
if (0 == s_buf_point[i][j]) {
flg = 0;
break;
}
}
if (flg) {
s_score++;
for (j = i; j > 0; j--) {
memcpy(s_buf_point[j], s_buf_point[j - 1], sizeof(s_buf_point[j]));
}
memset(s_buf_point[0], '\0', sizeof(s_buf_point[0]));
}
}
return 0;
}
static int cp_box()
{
int i;
for (i = 0; i < NUM_BOX; i++) {
s_buf_point[box[i].y][box[i].x] = 1;
box[i].x = 0;
box[i].y = 0;
}
return 0;
}
static int key_left()
{
int i;
t_box tmp[NUM_BOX];
memcpy(tmp, box, sizeof(box));
for (i = 0; i < NUM_BOX; i++) {
tmp[i].x--;
if (0 > tmp[i].x)
return -1;
if (1 == s_buf_point[tmp[i].y][tmp[i].x])
return -1;
}
for (i = 0; i < NUM_BOX; i++) {
box[i].x--;
}
return 0;
}
static int key_right()
{
int i;
t_box tmp[NUM_BOX];
memcpy(tmp, box, sizeof(box));
for (i = 0; i < NUM_BOX; i++) {
tmp[i].x++;
if (NUM_MAX_X <= tmp[i].x)
return -1;
if (1 == s_buf_point[tmp[i].y][tmp[i].x])
return -1;
}
for (i = 0; i < NUM_BOX; i++) {
box[i].x++;
}
return 0;
}
static int key_down()
{
int i, k, ret = 0;
t_box tmp[NUM_BOX];
memcpy(tmp, box, sizeof(box));
for (i = 0; i < NUM_BOX; i++) {
tmp[i].y++;
if (NUM_MAX_Y <= tmp[i].y) {
cp_box();
deal_score();
return 1;
}
if (1 == s_buf_point[tmp[i].y][tmp[i].x]) {
if (1 == tmp[i].y)
return -1;
cp_box();
deal_score();
return 1;
}
}
for (i = 0; i < NUM_BOX; i++) {
box[i].y++;
}
return 0;
}
static int key_revolve()
{
int i, x, y;
t_box tmp[NUM_BOX], center;
memcpy(tmp, box, sizeof(box));
center = box[0];
for (i = 0; i < NUM_BOX; i++) {
x = tmp[i].x - center.x;
y = tmp[i].y - center.y;
tmp[i].x = center.x + y;
tmp[i].y = center.y - x;
}
for (i = 0; i < NUM_BOX; i++) {
if (NUM_MAX_X <= tmp[i].x || 0 > tmp[i].x)
return -1;
if (1 == s_buf_point[tmp[i].y][tmp[i].x])
return -1;
}
for (i = 0; i < NUM_BOX; i++) {
x = box[i].x - center.x;
y = box[i].y - center.y;
box[i].x = center.x + y;
box[i].y = center.y - x;
}
return 0;
}
static int deal_key(char *buf, int num)
{
int i, ret;
for (i = 0; i < num; i++) {
switch(buf[i]) {
case CHAR_A:
case CHAR_LEFT:
key_left();
break;
case CHAR_D:
case CHAR_RIGHT:
key_right();
break;
case CHAR_SPACE:
key_revolve();
break;
case CHAR_S:
case CHAR_DOWN:
ret = key_down();
if (0 > ret)
return ret;
break;
case CHAR_Q:
return -1;
default:
break;
}
}
if (0 >= num){
ret = key_down();
if (0 > ret)
return ret;
}
return 0;
}
static int paint_box(int y, int x)
{
int i;
if (box[0].x == box[1].x && box[0].y == box[1].y)
return -1;
for(i = 0; i < NUM_BOX; i++) {
if (x == box[i].x && y == box[i].y) {
printf(BLUE STR_BOX NONE);
return 0;
}
}
return -1;
}
static int paint()
{
int i, j, k, ret;
//printf("\033[0;0H\033[K");
MOVETO(0,0);
for(i = 0; i < NUM_MAX_X + 2; i++)
printf(RED STR_FRAME_X NONE);
//printf("\33[0;%dH\33[K-",i);
CLEAR_TAIL();
printf(ENTER);
for(i = 0; i < NUM_MAX_Y; i++) {
printf(RED STR_FRAME_Y NONE);
for(j=0; j < NUM_MAX_X; j++) {
if(0 == s_buf_point[i][j]) {
ret = paint_box(i, j);
if (ret)
printf(STR_POINT);
} else
printf(BLUE STR_BOX NONE);
}
if(10 == i)
printf(RED STR_FRAME_Y " 得分: %d" NONE, s_score);
else if(7 == i)
printf(RED STR_FRAME_Y NONE LIGHT_BLUE" Press 'q' to quit!" NONE);
else
printf(RED STR_FRAME_Y NONE);
CLEAR_TAIL();
printf(ENTER);
}
for(i = 0; i < NUM_MAX_X + 2; i++)
printf(RED STR_FRAME_X NONE);
CLEAR_TAIL();
fflush(stdout);
return 0;
}
static int create_box()
{
int i;
for (i = 0; i < NUM_BOX; i++) {
if (box[i].x || box[i].y)
return -1;
}
srand((unsigned)time(NULL));
i = 1+ rand() % 7;
switch(i) {
case 1: //L
box[0].x = NUM_MAX_X / 2;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2;
box[1].y = 1;
box[2].x = NUM_MAX_X / 2;
box[2].y = 2;
box[3].x = NUM_MAX_X / 2 + 1;
box[3].y = 2;
break;
case 2: //反L
box[0].x = NUM_MAX_X / 2;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2 + 1;
box[1].y = 0;
box[2].x = NUM_MAX_X / 2;
box[2].y = 1;
box[3].x = NUM_MAX_X / 2;
box[3].y = 2;
break;
case 3: //Z
box[0].x = NUM_MAX_X / 2 - 1;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2;
box[1].y = 0;
box[2].x = NUM_MAX_X / 2;
box[2].y = 1;
box[3].x = NUM_MAX_X / 2 + 1;
box[3].y = 1;
break;
case 4: //反Z
box[0].x = NUM_MAX_X / 2;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2 + 1;
box[1].y = 0;
box[2].x = NUM_MAX_X / 2;
box[2].y = 1;
box[3].x = NUM_MAX_X / 2 - 1;
box[3].y = 1;
break;
case 5: //田
box[0].x = NUM_MAX_X / 2;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2 + 1;
box[1].y = 0;
box[2].x = NUM_MAX_X / 2;
box[2].y = 1;
box[3].x = NUM_MAX_X / 2 + 1;
box[3].y = 1;
break;
case 6: //1
box[0].x = NUM_MAX_X / 2;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2;
box[1].y = 1;
box[2].x = NUM_MAX_X / 2;
box[2].y = 2;
box[3].x = NUM_MAX_X / 2;
box[3].y = 3;
break;
case 7: //山
box[0].x = NUM_MAX_X / 2 - 1;
box[0].y = 0;
box[1].x = NUM_MAX_X / 2;
box[1].y = 0;
box[2].x = NUM_MAX_X / 2 + 1;
box[2].y = 0;
box[3].x = NUM_MAX_X / 2;
box[3].y = 1;
break;
default:
break;
}
return 0;
}
int main()
{
int ret, num;
char key[NUM_MAX_KEY];
fflush(stdout);
//system("clear");
CLEAR();
HIDE_CURSOR();
fflush(stdout);
termios_init();
while(1)
{
create_box();
ret = get_key(key, &num);
if (0 > ret) {
printf("err\n");
break;
}
ret = deal_key(key, num);
if (0 > ret) {
printf("game over!\n");
break;
}
// 保存光标貌似无效 printf光标移位好像0和1是一样的
ret = paint();
}
termios_recover();
return 0;
}