📄 tetris.c
字号:
/**
* Title: tetris.c
* Type: GCC (*.c)
* Description:
* Copyright: Copyright (c) 2003
* Company: djws
* author djws
* version 1.1
*/
/* if you include "curses.h"
to compile this file, you need use the command
cc [file.c] -lcurses -ltermcap
*/
/* delete the file you don't need */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//#include <errno.h>
#include <string.h>
//#include <time.h>
//#include <sys/types.h>
//#include <sys/socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
//#include <signal.h>
#include <curses.h>
//#include <sys/ioctl.h>
//#include <termio.h>
/* add you own head file */
//#include "tetris.h"
typedef struct {
int x;
int y;
int flag;
} Block;
typedef struct {
char username[20];
int score;
} History;
typedef struct {
/* 0: one player
1: two player
*/
int players;
/* 0: Normal
1: SpeedUp
2: Horrible
*/
int mode;
/* 0-9 */
int speed;
/* 0: retrorse
1: direct
*/
int rotate;
/* 0-12 */
int level;
/* speed up scale */
int scale;
} Options;
#define RETRORSE(flag) (bdata[flag][4][0]) //get new block
#define DIRECT(flag) (bdata[flag][4][1])
#define XOFF(flag, i) (bdata[flag][i][0]) //get block position
#define YOFF(flag, i) (bdata[flag][i][1])
// menu entry
#define MAXM 4
// option entry
#define MAXOM 7
// temp string length
#define MAXLEN 50
// container scale 12*21
#define CONX 21
#define CONY 12
// menu scale 18*47
#define MEUX 18
#define MEUY 47
// screen scale 100*33
#define SCRX 33
#define SCRY 100
// level up step
#define LEVELUP opt.scale
int block_check(Block* blk); //check the block can be put to container or not
int block_rand(); //get a random flag (18 is not allowed);
int block_ctrl(WINDOW *win, Block* blk, int cmd);
int block_clear(WINDOW *win, Block* blk); //clear the block on the screen
int block_draw(WINDOW *win, Block* blk); //draw the block on the screen
int block_left(WINDOW *win, Block* blk); //block move left
int block_right(WINDOW *win, Block* blk); //block move right
int block_down(WINDOW *win, Block* blk); //block descend
int block_drop(WINDOW *win, Block* blk); //block landfall
int block_rotate(WINDOW *win, Block* blk, int dec); //block rotate
void map_set(int x, int y); // set appointed cell
void map_clr(int x, int y); // clear appointed cell
unsigned char map_get(int x, int y); //get appointed cell
void map_clear(); // clear the container
void map_init(); // init the container
void map_fill(Block* blk); //put the block into the container
int map_refresh(); // clear the full line
void screen_redraw(WINDOW *main, WINDOW *container, long points, long lines);
void game_end();
void row_left(int xz, WINDOW *win, char *str);
void row_right(int xz, WINDOW *win, char *str);
void play();
void history();
void options();
void menu();
/* I want to use someone's data first, but I find that I cann't understand it, so I create my own */
/* these codes is so silly, and me too */
/* the struct is {{x0,y0}, {x1,y1}, {x2,y2}, {x3,y3}, {retrorse,direct}} */
static int bdata[19][5][2] = { // shape flag
{{0,0}, {0,1}, {1,0}, {1,1}, {0,0}}, // "■■" 0
// "■■"
{{0,2}, {1,0}, {1,1}, {1,2}, {2,4}}, // " ■" 1
// "■■■"
{{0,0}, {0,1}, {1,1}, {2,1}, {3,1}}, // "■■" 2
// " ■"
// " ■"
{{0,0}, {0,1}, {0,2}, {1,0}, {4,2}}, // "■■■" 3
// "■ "
{{0,0}, {1,0}, {2,0}, {2,1}, {1,3}}, // "■ " 4
// "■ "
// "■■"
{{0,0}, {1,0}, {1,1}, {1,2}, {6,8}}, // "■ " 5
// "■■■"
{{0,1}, {1,1}, {2,0}, {2,1},{7,5}}, // " ■" 6
// " ■"
// "■■"
{{0,0}, {0,1}, {0,2}, {1,2}, {8,6}}, // "■■■" 7
// " ■"
{{0,0}, {0,1}, {1,0}, {2,0}, {5,7}}, // "■■" 8
// "■ "
// "■ "
{{0,1}, {1,0}, {1,1}, {1,2}, {10,12}}, // " ■ " 9
// "■■■"
{{0,1}, {1,0}, {1,1}, {2,1}, {11,10}}, // " ■" 10
// "■■"
// " ■"
{{0,0}, {0,1}, {0,2}, {1,1}, {12,10}}, // "■■■" 11
// " ■ "
{{0,0}, {1,0}, {1,1}, {2,0}, {9,11}}, // "■ " 12
// "■■"
// "■ "
{{0,0}, {0,1}, {1,1}, {1,2}, {14,14}}, // "■■ " 13
// " ■■"
{{0,1}, {1,0}, {1,1}, {2,0}, {13,13}}, // " ■" 14
// "■■"
// "■ "
{{0,1}, {0,2}, {1,0}, {1,1}, {16,16}}, // " ■■" 15
// "■■ "
{{0,0}, {1,0}, {1,1}, {2,1}, {15,15}}, // "■ " 16
// "■■"
// " ■"
//17 and 18 is special
{{0,0}, {0,1}, {0,2}, {0,3}, {18,18}}, // "■■■■" 17
{{0,0}, {1,0}, {2,0}, {3,0}, {17,17}} // " ■ " 18
// " ■ "
// " ■ "
// " ■ "
};
/* the container */
unsigned char map[CONX][CONY];
/* game options
default:
one player
SpeedUp mode
speed 0
level 0
scale 50
*/
static Options opt;
/* now it's the menu */
void
menu() {
int i = 0;
char *menustr[MAXM];
char tmp[MAXLEN];
WINDOW *win;
int xz=0;
menustr[0] = "Play";
menustr[1] = "History";
menustr[2] = "Options";
menustr[3] = "Exit";
opt.players = 0;
opt.mode = 1;
opt.speed = 0;
opt.rotate = 0;
opt.level = 0;
opt.scale = 50;
initscr();
while(1) {
win=newwin(MEUX, MEUY, (SCRX-MEUX)/2, (SCRY-MEUY)/2);
box(win, 0, 0);
strcpy(tmp, "Tetris for UNIX");
mvwprintw(win,
2, (MEUY-strlen(tmp))/2,
tmp);
strcpy(tmp, "Copyright (C) 2002-2003 djws");
mvwprintw(win,
4, (MEUY-strlen(tmp))/2,
tmp);
strcpy(tmp, "All Rights Reserved");
mvwprintw(win,
6, (MEUY-strlen(tmp))/2,
tmp);
mvwprintw(win,
8, 1,
"*********************************************");
keypad(win, TRUE);
for(i=0; i<2*MAXM; i+=2) { /* 显示菜单内容 */
strcpy(tmp, menustr[i/2]);
mvwaddstr(win,
i+9, (MEUY-strlen(tmp))/2,
tmp);
}
wstandout(win); /* 开始反相显示 */
strcpy(tmp, menustr[xz]);
mvwaddstr(win,
2*xz+9, (MEUY-strlen(tmp))/2,
tmp); /* 反相显示第一个菜单 */
wstandend(win); /* 结束反相显示 */
switch(wgetch(win)) { /* 读用户输入 */
case KEY_LEFT: /* KEY_LEFT、KEY_UP、KEY_DOWN、KEY_RIGHT为光标移动键 */
case KEY_UP:
wstandend(win); /* 正常显示上一菜单 */
strcpy(tmp, menustr[xz]);
mvwaddstr(win,
2*xz+9, (MEUY-strlen(tmp))/2,
tmp);
wmove(win,
2*xz+9, (MEUY-strlen(tmp))/2);
wstandout(win);
wrefresh(win); /* 刷新当前窗口 */
if(xz == 0)
xz = MAXM-1;
else
xz--; /* 判断是否为第一个菜单,决定光标走向 */
wstandout(win); /* 反白显示当前菜单 */
strcpy(tmp, menustr[xz]);
mvwaddstr(win,
2*xz+9, (MEUY-strlen(tmp))/2,
tmp);
wmove(win,
2*xz+9, (MEUY-strlen(tmp))/2);
wstandend(win);
wrefresh(win);
break; /* 刷新当前窗口 */
case KEY_RIGHT:
case KEY_DOWN:
wstandend(win);
strcpy(tmp, menustr[xz]);
mvwaddstr(win,
2*xz+9, (MEUY-strlen(tmp))/2,
menustr[xz]);
wmove(win,
2*xz+9, (MEUY-strlen(tmp))/2);
wrefresh(win);
wstandout(win);
if(xz == MAXM-1)
xz = 0;
else
xz++;
wstandout(win);
strcpy(tmp, menustr[xz]);
mvwaddstr(win,
2*xz+9, (MEUY-strlen(tmp))/2,
menustr[xz]);
wmove(win,
2*xz+9, (MEUY-strlen(tmp))/2);
wstandend(win);
wrefresh(win);
break;
case 10: /* 如输入回车键则执行不同的函数 */
switch(xz) {
case 0:
wclear(win);
wrefresh(win);
keypad(win, FALSE);
play();
keypad(win, TRUE);
touchwin(win);
wclear(win);
wrefresh(win);
break;
case 1:
wclear(win);
wrefresh(win);
keypad(win, FALSE);
history();
keypad(win, TRUE);
touchwin(win);
wclear(win);
wrefresh(win);
break;
case 2:
wclear(win);
wrefresh(win);
keypad(win, FALSE);
options();
keypad(win, TRUE);
touchwin(win);
wclear(win);
wrefresh(win);
break;
case 3:
touchwin(win);
wclear(win);
wrefresh(win);/* 结束游戏 */
cbreak();
echo();
endwin();
exit(0); /* 结束画形操作方式,退出 */
} //end switch(xz)
break;
default:
//beep();
noecho();
break; /* 无效输入,不显示并响铃提醒 */
} //end switch(wgetch(win))
} //end while(1)
} //end menu()
int
block_check(Block* blk) {
if(((blk->x)<0) || ((blk->y)<0))
return 0;
if(((blk->x)>=CONX) || ((blk->y)>=CONY))
return 0;
int x = 0;
int y = 0;
int i = 0;
for(i=0; i<4; i++) {
x = (blk->x)+XOFF(blk->flag, i);
y = (blk->y)+YOFF(blk->flag, i);
if((x<0) || (y<0))
return 0;
if((x>=CONX) || (y>=CONY))
return 0;
if(map[x][y] == 1)
//map_get(x, y);
return 0;
}
return 1;
}
/* return a random flag number */
/* there are 7 kinds of basic shape, all the shape has the same probability */
/* for more fun, flag==18 is not allowed */
int
block_rand() {
int flag = 0;
srand((unsigned)time(NULL));
flag = (rand()%28);
switch(flag) {
case 19:
case 20:
case 21:
return 0;
case 22:
return 13;
case 23:
return 14;
case 24:
return 15;
case 25:
return 16;
case 18:
case 26:
case 27:
return 17;
default:
return flag;
};
}
/* the interface doesn't seem beautiful, but the funciton can be modified later */
/* now it just return 0, but for future, so all the function which use it return a int variable */
int
block_ctrl(WINDOW *win, Block* blk, int cmd) {
int i = 0;
char z[3] = "■";
if(cmd == 0)
strcpy(z, " ");
for(i=0; i<4; i++) {
mvwaddstr(win,
(blk->x)+XOFF(blk->flag, i)+1, (blk->y)*2+YOFF(blk->flag, i)*2+1,
z);
}
wmove(win, 0, 0);
return 0;
}
int
block_clear(WINDOW *win, Block* blk) {
return block_ctrl(win, blk, 0);
}
int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -