#include
#include
#include
#include
#include
#include
#include
enum {
S_VERTICAL,
S_HORIZON,
S_SQUARE,
S_THUNDER_1,
S_THUNDER_2,
S_THUNDER_3,
S_THUNDER_4,
S_EL_1,
S_EL_2,
S_EL_3,
S_EL_4,
S_EL_5,
S_EL_6,
S_EL_7,
S_EL_8,
S_TBRANCH_1,
S_TBRANCH_2,
S_TBRANCH_3,
S_TBRANCH_4,
};
enum {
LEFT,
RIGHT,
DOWN,
UP
};
typedef struct point {
int x;
int y;
}point;
struct shape {
int type;
point point[4];
int sid;
};
struct shape smap[] = {
{0,0,0,1,0,2,0,3,0,0},
{1,0,3,0,2,0,1,0,0,0},
{2,0,0,0,1,1,0,1,1,0},
{3,0,1,1,0,1,1,2,0,0},
{4,2,2,1,1,2,1,1,0,0},
{5,0,0,1,0,1,1,2,1,0},
{6,1,2,1,1,2,1,2,0,0},
{7,1,2,2,0,2,1,2,2,0},
{8,2,1,0,0,1,0,2,0,0},
{9,2,0,1,2,1,1,1,0,0},
{10,0,0,2,1,1,1,0,1,0},
{11,1,0,2,0,2,1,2,2,0},
{12,0,1,0,0,1,0,2,0,0},
{13,2,2,1,2,1,1,1,0,0},
{14,2,0,2,1,1,1,0,1,0},
{15,1,1,2,0,2,1,2,2,0},
{16,1,1,0,0,1,0,2,0,0},
{17,1,1,0,2,0,1,0,0,0},
{18,1,0,2,1,1,1,0,1,0}
};
int bitmap[20][10];
pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER;
struct shape curshape, nextshape;
int g_id = 1;
int score = 0;
int level = 1;
int linestat[20] = {0};
int leftedge = 0, rightedge = 0, bottom = 0;;
long long lasttime = 0;
int state;
int nexts;
struct termios new_setting,init_setting;
void clear_full_line();
int next_shape(int curs)
{
switch (curs) {
case S_HORIZON:
case S_THUNDER_2:
case S_THUNDER_4:
return curs - 1;
case S_EL_4:
case S_EL_8:
case S_TBRANCH_4:
return curs - 3;
case S_SQUARE:
return curs;
default:
return curs + 1;
}
}
void draw_bitmap()
{
int i, j, k;
printf("\033[2J");
int news[4][4] = {0};
for (i = 0; i < 4; i++) {
news[smap[nexts].point[i].x][smap[nexts].point[i].y] = 1;
}
for (i = 0; i < 4; i++) {
printf(" ");
for (j = 0; j < 4; j++) {
if (news[i][j]) {
printf("[]");
} else {
printf(" ");
}
}
printf("\n");
}
write(1, "---------------------\n", sizeof("---------------------\n"));
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
write(1, bitmap[i][j] ? "[]" : " ", 2);
if (j == 9) write(1, "|\n", 2);
}
}
write(1, "---------------------\n", sizeof("---------------------\n"));
printf("Score:%d Level:%d\n", score, level);
}
long long gettime_ms()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
int random_shape()
{
srand(gettime_ms());
return (int)(rand() % 18);
}
int generate_new_shape()
{
int i;
curshape.type = nexts;
curshape.sid = g_id;
nexts = random_shape();
for (i = 0; i < 4; i++) {
curshape.point[i].x = smap[curshape.type].point[i].x;
linestat[curshape.point[i].x]++;
curshape.point[i].y = smap[curshape.type].point[i].y + 3;
if (bitmap[curshape.point[i].x][curshape.point[i].y]) {
tcsetattr(0, TCSANOW, &init_setting);
printf("Game Over!\n");
exit(0);
}
bitmap[curshape.point[i].x][curshape.point[i].y] = curshape.sid;
}
leftedge = rightedge = bottom = 0;
lasttime = gettime_ms();
g_id++;
return 0;
}
void update_bitmap()
{
int i, j;
for (i = 0; i < 4; i++) {
bitmap[curshape.point[i].x][curshape.point[i].y] = 0;
linestat[curshape.point[i].x]--;
curshape.point[i].x = nextshape.point[i].x;
curshape.point[i].y = nextshape.point[i].y;
}
for (i = 0; i < 4; i++) {
bitmap[curshape.point[i].x][curshape.point[i].y] = curshape.sid;
linestat[curshape.point[i].x]++;
}
}
void clear_full_line()
{
int i = 19, j = 19;
int fulcnt = 0;
int tmpb[20][10] = {0};
while (i >= 0) {
if (linestat[i] != 10) {
memcpy(tmpb[j], bitmap[i], sizeof(tmpb[j]));
j--;
} else {
score += 10;
fulcnt++;
}
i--;
}
if (fulcnt) {
memcpy(bitmap, tmpb, sizeof(bitmap));
memset(linestat, 0, sizeof(linestat));
for (i = 0; i < 20; i++)
for (j = 0; j < 10; j++)
if (bitmap[i][j]) linestat[i]++;
}
}
void OnKeyDown(int key)
{
int i, j;
pthread_mutex_lock(&mlock);
if (bottom && gettime_ms() - lasttime > 500) {
clear_full_line();
if (generate_new_shape()) {
pthread_mutex_unlock(&mlock);
return;
}
goto draw;
}
if (key == LEFT) {
if (leftedge) {
goto draw;
}
int cnt = 0;
for (i = 0; i < 4; i++) {
nextshape.point[i].x = curshape.point[i].x;
nextshape.point[i].y = curshape.point[i].y - 1;
if (nextshape.point[i].y < 0 ||
(bitmap[nextshape.point[i].x][nextshape.point[i].y] > 0 && bitmap[nextshape.point[i].x][nextshape.point[i].y] != curshape.sid)) {
leftedge = 1;
}
if (bottom) {
if (bitmap[nextshape.point[i].x + 1][nextshape.point[i].y] == curshape.sid ||
bitmap[nextshape.point[i].x + 1][nextshape.point[i].y] == 0) cnt++;
}
}
if (cnt >= 4) {
bottom = 0;
}
if (!leftedge) {
rightedge = 0;
update_bitmap();
}
} else if (key == RIGHT) {
if (rightedge) {goto draw;};
int cnt = 0;
for (i = 0; i < 4; i++) {
nextshape.point[i].x = curshape.point[i].x;
nextshape.point[i].y = curshape.point[i].y + 1;
if (nextshape.point[i].y >= 10 ||
(bitmap[nextshape.point[i].x][nextshape.point[i].y] > 0 && bitmap[nextshape.point[i].x][nextshape.point[i].y] != curshape.sid)) {
rightedge = 1;
}
if (bottom) {
if (bitmap[nextshape.point[i].x + 1][nextshape.point[i].y] == curshape.sid ||
bitmap[nextshape.point[i].x + 1][nextshape.point[i].y] == 0) cnt++;
}
}
if (cnt >= 4) {
bottom = 0;
}
if (!rightedge) {
leftedge = 0;
update_bitmap();
}
} else if (key == DOWN) {
if (bottom) {goto draw;};
for (i = 0; i < 4; i++) {
nextshape.point[i].x = curshape.point[i].x + 1;
nextshape.point[i].y = curshape.point[i].y;
if (nextshape.point[i].x >= 20 ||
(bitmap[nextshape.point[i].x][nextshape.point[i].y] > 0 && bitmap[nextshape.point[i].x][nextshape.point[i].y] != curshape.sid)) {
bottom = 1;
lasttime = gettime_ms();
}
}
if (!bottom) {
update_bitmap();
}
} else if (key == UP) {
if (curshape.type == S_SQUARE) goto draw;
int s = curshape.type;
int next = next_shape(s);
for (i = 0; i < 4; i++) {
nextshape.point[i].x = curshape.point[i].x - smap[s].point[i].x + smap[next].point[i].x;
nextshape.point[i].y = curshape.point[i].y - smap[s].point[i].y + smap[next].point[i].y;
int startx = nextshape.point[i].x < curshape.point[i].x ? nextshape.point[i].x : curshape.point[i].x;
int starty = nextshape.point[i].y < curshape.point[i].y ? nextshape.point[i].y : curshape.point[i].y;
int j,k;
if (nextshape.point[i].y < 0) {
leftedge = 1;
goto draw;
}
if (nextshape.point[i].y >= 10) {
rightedge = 1;
goto draw;
}
if (nextshape.point[i].x >= 20) {
bottom = 1;
goto draw;
}
int size = s <= S_HORIZON ? 4 : 3;
for (j = startx; j < startx + size; j++)
for (k = starty; k < starty + size; k++)
if (bitmap[j][k] > 0 && bitmap[j][k] != curshape.sid) {
goto draw;
}
}
if (!(leftedge && rightedge && bottom)) {
curshape.type = next;
leftedge = rightedge = bottom = 0;
lasttime = gettime_ms();
update_bitmap();
}
}
if (leftedge && rightedge && bottom) {
clear_full_line();
if (generate_new_shape()) {
pthread_mutex_unlock(&mlock);
return;
}
}
draw:
draw_bitmap();
pthread_mutex_unlock(&mlock);
}
void *t_timer(void *arg)
{
while (1) {
if (state == 1) {
OnKeyDown(DOWN);
}
usleep((int)(1000000 * (1.0 / (float)(level))));
}
}
const char *startlogo = "\
************************************\n\
Welcome to Russia Square! *\n\
************************************\n\
LEFT:\ta\nRIGHT:\td\nDOWN:\ts\nROTATE:\tw\n\
PAUSE/RESUME:\tp\n\
Please select Level(>0):";
int main(void)
{
printf(startlogo);
scanf("%d", &level);
if (level <= 0) level = 1;
// disable echo
tcgetattr(0, &init_setting);
new_setting = init_setting;
new_setting.c_lflag &= ~(ECHO | ICANON);
tcsetattr(0, TCSANOW, &new_setting);
pthread_t tid;
nexts = random_shape();
generate_new_shape();
draw_bitmap();
state = 1;
usleep(500000);
pthread_create(&tid, NULL, t_timer, NULL);
while (1) {
char ch;
if (state != 1) {
ch = getchar();
if (ch == 'p') {
state = 1;
}
continue;
}
ch = getchar();
switch(ch) {
case 'a':
OnKeyDown(LEFT);
break;
case 'd':
OnKeyDown(RIGHT);
break;
case 's':
OnKeyDown(DOWN);
break;
case 'w':
OnKeyDown(UP);
break;
case 'p':
state = 2;
break;
}
}
exit:
printf("exit\n");
return 0;
}