俄罗斯方块(Tetris)

源自: http://hi.baidu.com/misaka20001/blog/item/a854150a49b6b9d87bcbe1b6.html#0

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>

char *gcText[] = {"■", "□", "□", "□", "□", "□", "□", "□"};

struct tetris {
	int x, y, s, st, t;
	int _pool[16][32], (*pool)[32], tmap[8][4][16];
} gt;

void trsInit(){
	// 方块形状定义 7种方块 4个方向, 采用4x4的方阵 二进制01存储
	int sp[8][4] = {{15,4369},{23,785,116,547},{71,275,113,802},
					{39,305,114,562},{54,561},{99,306},{51,51}, {-1/*结束标志*/}};
	int *p, i, j, b;
	// 补满四个方向
	for(p = sp[0]; *p >= 0; ++ p) if(!*p) *p = p[-2];

	// 4x4图形, 值对应gcText中的符号, 索引从1-7, 0为游戏区域
	for(j = 0; j < 7; ++j)
		for(i = 0; i < 4; ++i)
			for(b = 0; b < 16; ++b)
				gt.tmap[j+1][i][b] = (sp[j][i] & 1) * (j + 1), sp[j][i] >>= 1;

	// 游戏区域(10 x 21)/边界
	gt.pool = &gt._pool[4];
	memset(gt._pool, -1, sizeof(gt._pool)); // 边界填充为 -1 表示不绘制
	for(i = 0; i < 10; ++i) memset(gt.pool[i], 0, sizeof(int[21])); // 游戏区域 填充为0对应gcText中的符号
}

// 游戏区域符号操作, sp代表方块, c表示操作类型 0 简单的碰撞检测, 1 填充, 2 清空
int trsCopy(int sp[], int x, int y, int c){
	int i, cx, cy;
	for(i = 0; i < 16; ++i)
		if(sp[i]){
			cx = x + (i & 3), cy = y + (i >> 2);
			if(gt.pool[cx][cy])	// 已被占用
				if(c == 2)	// 清空
					gt.pool[cx][cy] = 0;
				else	// 返回 失败
					return 0;
			if(c == 1)	// 未被占用 并且填充
				gt.pool[cx][cy] = sp[i];
		}
	return 1;
}

int trsScene(){
	int x, y = 0, k = 0;
	COORD pos = {0};
	gt.s = rand() % 7 + 1, gt.st = gt.t = 0;
	gt.x = 3, gt.y = 0; // x, y为方块4x4第一元素的位置, 整个区域宽10, 高21
	for(--gt.t; ;Sleep(1), --gt.t, k = 0){
		while( kbhit() ){
			//k = getche();
			k = getch();
			switch(k){
			case 27: return 0;
			case 'A': case 'a': if(trsCopy(gt.tmap[gt.s][gt.st], gt.x - 1, gt.y, 0)) --gt.x; break;
			case 'D': case 'd': if(trsCopy(gt.tmap[gt.s][gt.st], gt.x + 1, gt.y, 0)) ++gt.x; break;
			case 'W': case 'w': if(trsCopy(gt.tmap[gt.s][(gt.st+1)%4], gt.x, gt.y, 0)) gt.st = (gt.st+1)%4; break;
			}
		}
		if(k == 's' || k == 'S' || gt.t < 0){	// 降落
			if(trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y + 1, 0)) // 检测填充
				++gt.y, gt.t = 50;
			else { // 填充, 判断整行并清除
				trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
				if(y == 0) return 0; // game over, y == 0 or y == 21
				for(--y; y > 0; --y){
					for(x = 0; gt.pool[x][y] > 0; ++x) ;
					if(gt.pool[x][y] < 0) // 表明循环到边界了, 是整行可以清除
						for(k = y++; k > 0; --k)
							for(x = 0; gt.pool[x][0] >= 0; ++x)
								gt.pool[x][k] = gt.pool[x][k - 1];
				}
				return 1;
			}
		}
		// 填充-绘制-清空
		trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 1);
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
		for(y = 1; gt.pool[0][y] >= 0; ++y, putchar(10)) // 绘制从[0~9][1~20]
			for(x = 0; gt.pool[x][0] >= 0; ++x)
				printf(gcText[gt.pool[x][y]]);
		trsCopy(gt.tmap[gt.s][gt.st], gt.x, gt.y, 2);
	}
	return 1;
}

int main(int argv, char** argc){
	srand(time(NULL));
	for(trsInit(); trsScene(););
	printf("Game Over\n");
	system("pause");
	return 0;
}

 

posted @ 2012-06-18 18:50  消烟客  阅读(224)  评论(0编辑  收藏  举报