⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tetris.c

📁 该程序是在linux下运行的俄罗斯方块游戏的原代码
💻 C
📖 第 1 页 / 共 3 页
字号:
block_draw(WINDOW *win, Block* blk) {
	return block_ctrl(win, blk, 1);
}

int
block_left(WINDOW *win, Block* blk) {
	(blk->y)--;
	if(block_check(blk) == 1) {
		(blk->y)++;
		if(block_clear(win, blk) == -1)
			return -1;
		(blk->y)--;
		if(block_draw(win, blk) == -1)
			return -1;
	}
	else {
		(blk->y)++;
	}
	return 0;
}

int
block_right(WINDOW *win, Block* blk) {
	(blk->y)++;
	if(block_check(blk) == 1) {
		(blk->y)--;
		if(block_clear(win, blk) == -1)
			return -1;
		(blk->y)++;
		if(block_draw(win, blk) == -1)
			return -1;
	}
	else {
		(blk->y)--;
	}
	return 0;
}

/* return -1: error 
 *	      15: descend
 *         n: the number of the deleted lines
 */
int
block_down(WINDOW *win, Block* blk) {
	(blk->x)++;
	if(block_check(blk) == 1) {
		(blk->x)--;
		if(block_clear(win, blk) == -1)
			return -1;
		(blk->x)++;
		if(block_draw(win, blk) == -1)
			return -1;
		return 0x0f;
	}
	(blk->x)--;
	map_fill(blk);
	return map_refresh();
}

int
block_drop(WINDOW *win, Block* blk) {
	if(block_clear(win, blk) == -1)
		return -1;
	while(block_check(blk) == 1) {
		(blk->x)++;
	}
	(blk->x)--;
	if(block_draw(win, blk) == -1) 
		return -1;
	map_fill(blk);
	return map_refresh();
}

int
block_rotate(WINDOW *win, Block* blk, int dec) {
	int oldflag = blk->flag;
	if(dec == 0) 
		blk->flag = RETRORSE(blk->flag);
	else
		blk->flag = DIRECT(blk->flag);
	/* but when flag equals 17 and 18 ,the situation is special, we need more codes to deal with it */
	if(blk->flag == 18) {
		(blk->x)-=2;
		(blk->y)+=2;
	}
	if(blk->flag == 17) {
		(blk->x)+=2;
		(blk->y)-=2;
	}
	if(block_check(blk) == 1) {
		int tmp = blk->flag;
		blk->flag = oldflag;
		if(tmp == 18) {
			(blk->x)+=2;
			(blk->y)-=2;
		}
		if(tmp == 17) {
			(blk->x)-=2;
			(blk->y)+=2;
		}
		if(block_clear(win, blk) == -1)
			return -1;
		blk->flag = tmp;
		if(tmp == 18) {
			(blk->x)-=2;
			(blk->y)+=2;
		}
		if(tmp == 17) {
			(blk->x)+=2;
			(blk->y)-=2;
		}
		if(block_draw(win, blk) == -1)
			return -1;
	}
	else {
		if(blk->flag == 18) {
			(blk->x)+=2;
			(blk->y)-=2;
		}
		if(blk->flag == 17) {
			(blk->x)-=2;
			(blk->y)+=2;
		}
		blk->flag = oldflag;
	}
	return 0;
}

/* the followed three function are not efficient, if you what the game runs faster,  
   you can use 'map[x][y]' in the function 'map_fill()', 'map_init()' directly
 */
void
map_set(int x, int y) {
	if(x<0)
		x = 0;	
	if(y<0)
		y = 0;
	if(x>=CONX)
		x = (CONX-1);	
	if(y>=CONY)
		y = (CONY-1);
	map[x][y] = 1;
}

void
map_clr(int x, int y) {
	if(x<0)
		x = 0;	
	if(y<0)
		y = 0;
	if(x>=CONX)
		x = (CONX-1);	
	if(y>=CONY)
		y = (CONY-1);
	map[x][y] = 0;
}

unsigned char
map_get(int x, int y) {
	return map[x][y];
}

/* in followed two function, I don't use 'map_set()' or 'map_clr()' */
void
map_clear() {
	int i = 0;
	int j = 0;
	for(i=0; i<CONX; i++)
		for(j=0; j<CONY; j++)
			map[i][j] = 0;
			//map_clr(i, j);
}

void
map_init() {
	int i = 0;
	int j = 0;
	map_clear();
	srand((unsigned)time(NULL));
	for(i=CONX-1; i>=(CONX-opt.level); i--)
		for(j=0; j<CONY; j++)
			map[i][j] = (rand()%2);
}

void
map_fill(Block* blk) {
	int i = 0;
	int x = 0;
	int y = 0; 
	for(i=0; i<4; i++) {
		x = (blk->x)+XOFF(blk->flag, i);
		y = (blk->y)+YOFF(blk->flag, i);
		map[x][y] = 1;
		//map_set(x, y);
	}
}

/* the function map_set(), map_clr(), map_get(), we don't need them, why we reverse them ? 
   now we use array as the map, for some reason maybe we need more complex struct in the future,
   then we can modify our function
 */

/* return the number of the deleted lines */
int
map_refresh() {
	int i = 0;
	int j = 0;
	int k = 0;
	int count = 0;
	unsigned char tmp = 0;
	for(i=CONX-1; i>=0; i--) {
		for(j=0; j<CONY; j++) {
			tmp = map[i][j];
			//tmp = map_get(i, j);
			if(tmp == 0)
				break;
		}
		if(j != CONY)
			continue;
		for(k=i-1; k>=0; k--)
			for(j=0; j<CONY; j++)
				map[k+1][j] = map[k][j];
		count++;
		i++;
	}
	return count;
}

void
screen_redraw(WINDOW *main, WINDOW *container, long points, long lines) {
	int x = 0;
	int y = 0;
	/* refresh the container */
	touchwin(container);
	for(x=0; x<CONX; x++)
		for(y=0; y<CONY; y++)
			if(map[x][y] == 0)
				mvwaddstr(container, x+1, y*2+1, "  ");
			else
				mvwaddstr(container, x+1, y*2+1, "■");
	wrefresh(container);
	
	/* renew the score */
	//  | # | CONX | # |
	x = 1+2+1+CONX+1+2+1;
	//  | ## |  CONY  | ## | SB | ## |
	y = 1+10+1+CONY*2+1+10+1+10+1+10+1;
	touchwin(main);
	char s[10];
	switch(opt.mode) {
		case 0: strcpy(s, "Normal");break;
		case 1: strcpy(s, "SpeedUp");break;
		case 2: strcpy(s, "Horrible");break;
		default:
			strcpy(s, "Error");break;
	};
	mvwprintw(main, 1+2+1+CONX+1-5, 1+10+1+CONY*2+1+10, "Mode:   %s", s);
	mvwprintw(main, 1+2+1+CONX+1-4, 1+10+1+CONY*2+1+10, "Speed:  %d", opt.speed);
	mvwprintw(main, 1+2+1+CONX+1-3, 1+10+1+CONY*2+1+10, "Level:  %d", opt.level);
	mvwprintw(main, 1+2+1+CONX+1-2, 1+10+1+CONY*2+1+10, "Score:  %d", points);
	mvwprintw(main, 1+2+1+CONX+1-1, 1+10+1+CONY*2+1+10, "Lines:  %d", lines);
	wrefresh(main);
	touchwin(container);
}

void
game_end(WINDOW *main, WINDOW *container, long points, long lines) {
	touchwin(container);
	map_clear();
	screen_redraw(main, container, points, lines);
	mvwaddstr(container, (CONX/2)+1, (CONY*2+2-strlen("Game Over"))/2, "Game Over");
	mvwaddstr(container, (CONX/2)+2, (CONY*2+2-strlen("Wait for 3 seconds..."))/2, "Wait for 3 seconds...");
	wrefresh(container);
	sleep(3);
	
	/* there are still some codes for store... */
	
	
	return;
}

void
play() {
	int x = 0;
	int y = 0;
	long points = 0L;    // points get
	long lines = 0L;    // lines kill
	int count = 0;    //counter for interval
	long startpoint = 0L;    //for level up
	map_init();
	//  | # | CONX | # |
	x = 1+2+1+CONX+1+2+1;
	//  | ## |  CONY  | ## | SB | ## |
	y = 1+10+1+CONY*2+1+10+1+10+1+10+1;
	WINDOW *main = newwin(x, y, (SCRX-x)/2, (SCRY-y)/2);    // main window
	box(main, 0, 0);	
	touchwin(main);
	wrefresh(main);
	WINDOW *container = newwin(1+CONX+1, 1+CONY*2+1, (SCRX-x)/2+1+2, (SCRY-y)/2+1+10);    // container
	box(container, 0, 0);
	touchwin(container);
	screen_redraw(main, container, points, lines);
	wrefresh(container);
	WINDOW *subwin = newwin(1+5+1, 1+10+1, (SCRX-x)/2+1+2, (SCRY-y)/2+1+10+1+CONY*2+1+10);    // sub window
	box(subwin, 0, 0);
	touchwin(subwin);
	wrefresh(subwin);
	keypad(container, TRUE);
	Block blk;    // current block
	blk.x = 0;
	blk.y = CONY/2+1;
	blk.flag = block_rand();
	if(blk.flag == 17)
		(blk.y)--; 
	touchwin(container);
	block_draw(container, &blk);    // show current block in container
	wrefresh(container);
	Block nextblk;    // next block
	nextblk.x = 0;
	nextblk.y = 0;
	nextblk.flag = block_rand();
	/* impossiable */
	if(block_check(&blk) == 0) {
		game_end(main, container, points, lines);
		keypad(container, FALSE);
		touchwin(container);
		wclear(container);
		wrefresh(container);
		delwin(container);    // delete container 
		touchwin(subwin);
		wclear(subwin);
		wrefresh(subwin);
		delwin(subwin);    //delete sub window
		touchwin(main);
		wclear(main);
		wrefresh(main);
		delwin(main);    //delete main window
		return;
	}
	int tmp = 0;
	int pf = 0;    // pause flag
	halfdelay(1);    // set halfdelay mode to realize block auto down
	touchwin(main);
	char s[10];
	switch(opt.mode) {
		case 0: strcpy(s, "Normal");break;
		case 1: strcpy(s, "SpeedUp");break;
		case 2: strcpy(s, "Horrible");break;
		default:
			strcpy(s, "Error");break;
	};
	mvwprintw(main, 1+2+1+CONX+1-5, 1+10+1+CONY*2+1+10, "Mode:   %s", s);
	mvwprintw(main, 1+2+1+CONX+1-4, 1+10+1+CONY*2+1+10, "Speed:  %d", opt.speed);
	mvwprintw(main, 1+2+1+CONX+1-3, 1+10+1+CONY*2+1+10, "Level:  %d", opt.level);
	mvwprintw(main, 1+2+1+CONX+1-2, 1+10+1+CONY*2+1+10, "Score:  %d", points);
	mvwprintw(main, 1+2+1+CONX+1-1, 1+10+1+CONY*2+1+10, "Lines:  %d", lines);
	wrefresh(main);
	touchwin(subwin);
	block_draw(subwin, &nextblk);    // show next block in sub window
	wrefresh(subwin);
	touchwin(container);
	while(1) {
		switch (wgetch(container)) {
			/* up arrow */
			case KEY_UP:
				if(pf == 1)    // pause mode check
					break;
				block_rotate(container, &blk, opt.rotate);
				break;
			/* auto down */
			case ERR:
				if(pf == 1)
					break;
				count++;
				if(count < (10-opt.speed))
					break;
				count = 0;
			/* down arrow */
			case KEY_DOWN:
				if(pf == 1)
					break;
				if((tmp=block_down(container, &blk)) == 0x0f)    // block down
					break;
				if(tmp != 0) {    // lines delete
					points+=(tmp*2-1);
					lines+=tmp;
					if(opt.mode == 1) {
						if((lines-startpoint) >= LEVELUP) {
							startpoint+=LEVELUP;
							opt.speed++;
							if(opt.speed > 9)
								opt.speed = 9;
						}
					}
					for(x=0; x<30; x++)    //sleep 0.3 second
						usleep(10000);    
					screen_redraw(main, container, points, lines);    //redraw the screen
				}
				blk.x = 0;
				blk.y = CONY/2+1;
				blk.flag = nextblk.flag;    // next block to current block
				if(blk.flag == 17)    // flag == 17 is special
					(blk.y)--;
				touchwin(subwin);
				block_clear(subwin, &nextblk);
				nextblk.flag = block_rand();    // new next block
				block_draw(subwin, &nextblk);
				wrefresh(subwin);    // sub window refresh
				touchwin(container);
				block_draw(container, &blk);
				wrefresh(container);    // draw container
				if(block_check(&blk) == 0) {    // check game over
					game_end(main, container, points, lines);
					keypad(container, FALSE);
					touchwin(container);
					wclear(container);
					wrefresh(container);
					delwin(container);    // delete container 
					touchwin(subwin);
					wclear(subwin);
					wrefresh(subwin);
					delwin(subwin);    //delete sub window
					touchwin(main);
					wclear(main);
					wrefresh(main);
					delwin(main);    //delete main window
					return;
				}
				break;
			/* left arrow */
			case KEY_LEFT:
				if(pf == 1)
					break;
				block_left(container, &blk);
				break;
			/* right arrow */
			case KEY_RIGHT:
				if(pf == 1)
					break;
				block_right(container, &blk);
				break;
			/* drop */
			case ' ':
				noecho();
				if(pf == 1)
					break;
				tmp = block_drop(container, &blk);
				/* follow codes same as KEY_DOWN */				
				if(tmp != 0) {
					points+=(tmp*2-1);
					lines+=tmp;
					if(opt.mode == 1) {
						if((points-startpoint) >= LEVELUP) {
							startpoint+=LEVELUP;
							opt.speed++;
							if(opt.speed > 9)
								opt.speed = 9;
						}
					}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -