/********************************************************************************\
很久之前就想写“俄罗斯方块”了,现在终于写成了,呵呵 …… !本来在学 MFC
准备搞 Windows 编程离开DOS黑黑的界面,觉得还欠点什么没写,原来以前就打算要写
“俄罗斯方块”一直没写,于是学了点 MFC 就又钻进了DOS黑界面 …… 现在正值软考
前夕,哎,软考是没希望了,英语又差得要死,这些烦恼只有在沉醉于Make Code 时才
能彻底忘掉 ……
算法不是很好,处理按键不是很敏捷,于是编写对战程序的雄心在没有好算法之前
只好先打消了。放在这里希望初学者能有所收获 !
操作说明:回车键: 开始/暂停
向上的方向键: 方块变形
向下的的方向键: 快速下落
向左/向右的方向键:向左/右移动方块
编译环境: TC3
要求显示器能提供: 彩色 43/50 线文本模式否则程序将退出。
author:江南孤峰
data: 2007--5--17
转载请注明出处:http://blog.programfan.com/blog.asp?blogid=3511
修改请保留原作者信息,否则视为侵权 !
点击下载源代码
\********************************************************************************/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
/* 功能键定义 */
#define ESC 0x011b
#define QUICK_DOWN 0x5000 /* 砖块快速下降 */
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define UP 0x4800
#define ENTER 0x1c0d
#define COMMON_DOWN 0x0011 /* 普通速度下降 */
#define OK 1
#define MAX_X 10 /* 游戏区域的宽度 */
#define MAX_Y 18 /* 游戏区域的高度 */
#define BLOCK_COUNT 7 /* 游戏支持的砖块数目 */
#define INIT_SPEED 200 /* 游戏初始速度 */
#define TEXT_MODE 64 /* 43/50 的文本模式 */
#define ADD_SPEED 20 /* 每升一级速度的增大 */
#define BELL 7 /* 蜂鸣声 */
/***************************** 数 据 结 构 ************************************/
typedef struct{ /* 坐标点 */
int x,y;
}COORD;
typedef struct { /* 当前砖块的相关信息 */
int shape_n; /* 砖块的编号 */
int shape; /* 本砖块内的形状编号,用于变形 */
int shape_count; /* 砖块总共的变形方式 */
int left_top_x; /* 砖块 4*4 矩阵中的左上角在 矩阵 metrix */
int left_top_y; /* 中的位置,主要用于变形 */
COORD dest[4]; /* 4 表示构成每个砖块的字符数目 */
}BLOCK_INFO;
/***************************** 全 局 变 量 ************************************/
int edge_top,edge_down,edge_left,edge_right; /* 游戏区域屏幕坐标边界 */
int level, score, speed; /* 游戏的状态变量 */
char metrix[MAX_Y][MAX_X]; /* 游戏区域矩阵 */
char video[MAX_Y*MAX_X*2]; /* 用于屏幕数据移动 */
/* 方块用4*4矩阵表示。写成4*4矩阵就知道是什么形状了,block#x 记录了所有变
* 形。4*4 的矩阵浪费了很多的内存空间,就因为直线,不过以后可以添加更多的
* 方块。添加一个方块需要定义该方块的矩阵以及其变形,其变形数目注册到全局
* 数组 shape[],改变宏 BLOCK_COUNT ,以及在函数 Select_Block()和
* Get_New_Shape() 中添加代码 。
*/
char block1[][4][4] = { /* 直线 及其变形 */
{ 0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0 }, /* 注意编号一定要是 0 */
{ 0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0 }
};
char block2[][4][4] = { /* 田字形 */
{ 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 }
};
char block3[][4][4] = { /* L形及其变形 */
{ 1,0,0,0, 1,0,0,0, 1,1,0,0, 0,0,0,0 },
{ 1,1,1,0, 1,0,0,0, 0,0,0,0, 0,0,0,0 },
{ 0,1,1,0, 0,0,1,0, 0,0,1,0, 0,0,0,0 },
{ 0,0,0,0, 0,0,1,0, 1,1,1,0, 0,0,0,0 }
};
char block4[][4][4] = { /* T 形及其变形 */
{ 0,1,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0 },
{ 1,0,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0 },
{ 1,1,1,0, 0,1,0,0, 0,0,0,0, 0,0,0,0 },
{ 0,1,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0 }
};
char block5[][4][4] = {
{ 0,1,0,0, 0,1,1,0, 0,0,1,0, 0,0,0,0 },
{ 0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 }
};
char block6[][4][4] = { /* 反 L 形及其变形 */
{ 0,0,1,0, 0,0,1,0, 0,1,1,0, 0,0,0,0 },
{ 0,0,0,0, 1,0,0,0, 1,1,1,0, 0,0,0,0 },
{ 1,1,0,0, 1,0,0,0, 1,0,0,0, 0,0,0,0 },
{ 1,1,1,0, 0,0,1,0, 0,0,0,0, 0,0,0,0 }
};
char block7[][4][4] = { /* block5 的反形 */
{ 0,0,1,0, 0,1,1,0, 0,1,0,0, 0,0,0,0 },
{ 1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0 }
};
int shape[] = { 2,1,4,4,2,4,2 }; /* 每个砖块的变形数目 */
const char meter_char[] = {
1, 14, 3, 5, 6, '@', '*', 219
}; /* 构成砖块的字符表 */
const int block_char_count = 8; /* 构成砖快的字符数目 */
char block_char; /* 构成当前砖块的字符 */
/***************************** 函 数 定 义**************************************/
/* 初始化屏幕块背景色 */
void Init_Face_Block(int bkColor){
textbackground(bkColor);
clrscr();
}
/* 更新游戏成绩 */
void Update_Level_Score(void){
window(edge_left, edge_top-5, edge_right, edge_top-1);
textcolor(YELLOW);
Init_Face_Block(BLACK);
gotoxy(1,2); cprintf("Score:%d",score);
gotoxy(1,4); cprintf("Level:%d",level);
window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
}
/* 打印游戏区域边缘 */
void Print_Edge(void){
int x, y;
window(edge_left, edge_top+1, edge_right, edge_down);
textcolor(CYAN);
clrscr();
for(y = 1; y < MAX_Y; y++){
gotoxy(1,y);
putchar(block_char);
gotoxy(MAX_X+1,y);
putchar(block_char);
}
gotoxy(1, MAX_Y);
for(x = 1; x < MAX_X+2; x++)
putchar(block_char);
window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
textcolor(YELLOW);
Init_Face_Block(BLACK);
}
/* 初始化游戏状态数据 */
void Init_Game(void){
level = 1;
score = 0;
speed = INIT_SPEED;
block_char = meter_char[rand()%block_char_count];
memset(metrix,0,sizeof(char) * MAX_Y * MAX_X);
Update_Level_Score();
Print_Edge();
}
/* 打印相关文本 */
void Print_Text(void){
window(edge_left-20, edge_top-4, edge_left-2, edge_down-1);
textcolor(WHITE);
Init_Face_Block(BLACK);
gotoxy(1,2); cprintf(" FUNCTION KEY ");
gotoxy(1,4); cprintf("start game:[Enter] ");
gotoxy(1,6); cprintf("pause game:[Enter] ");
gotoxy(1,8); cprintf("exit game :[ Esc ] ");
gotoxy(1,10); cprintf("move left :[ %c ] ",27);
gotoxy(1,12); cprintf("move right:[ %c ] ",26);
gotoxy(1,14); cprintf("down quick:[ %c ] ",25);
gotoxy(1,16); cprintf("change shape : [%c] ",24);
window(edge_right+2, edge_top+1, edge_right+11, edge_down-1);
gotoxy(1,2); cprintf("QQ GROUP:");
gotoxy(1,4); cprintf(" 28011342 ");
gotoxy(1,6); cprintf("MY QQ:");
gotoxy(1,8); cprintf(" 403324669");
gotoxy(1,10); cprintf(" WISH YOU");
gotoxy(1,12); cprintf(" HAPPY");
gotoxy(1,14); cprintf(" !!!");
}
/* 初始化用户界面 */
void Init_Face(void){
textcolor(WHITE);
Init_Face_Block(BLACK);
gotoxy(edge_left-20, edge_top-8);
printf(" WELCOME TO PLAY THE GAME OF RUSSIA BLOCK !");
gotoxy(edge_left-18, edge_down+3);
printf(" CopyRight @ JianNanGuFeng (2007-2010) ");
gotoxy(edge_left-10, edge_down+5);
printf(" Email: lingdlz@163.com");
window(edge_left-21, edge_top-6, edge_right+12, edge_down+1);
Init_Face_Block(RED);
window(edge_left-20, edge_top-5, edge_right+11, edge_down);
Init_Face_Block(BLACK);
window(edge_left-1, edge_top-5, edge_left-1, edge_down);
Init_Face_Block(RED);
window(edge_right+1, edge_top-5, edge_right+1, edge_down);
clrscr();
window(edge_left, edge_top, edge_right+12, edge_top);
clrscr();
Print_Text();
}
/* 设置只需初始化一次的变量 */
void Configure_Game(void){
struct text_info text;
textmode(TEXT_MODE);
gettextinfo(&text);
if(text.screenheight != 43 && text.screenheight != 50){
puts("The Game Need Text 43/50 Mode !");
exit(0);
}
edge_top = (text.screenheight - MAX_Y+7) / 2;
edge_down = edge_top + MAX_Y;
edge_left = (text.screenwidth - MAX_X+6) / 2;
edge_right = edge_left + MAX_X;
}
/* 设置不合法光标尺寸,隐藏光标 */
void Hide_Cursor(void){
union REGS inregs,outregs;
inregs.h.ch = 100;
inregs.h.cl = 100;
inregs.h.ah = 1;
int86(0x10,&inregs,&outregs);
}
/* 砖块位置信息存入 pBlock->dest */
void Write_Block_Coord(char block[][4][4], BLOCK_INFO *pBlock){
int x, y, i, line_add = 3;
if(pBlock->shape_n == 0)
line_add = 4; /* 直线需要检查4*4的矩阵 */
for(i = y = 0; y < line_add; y++)
for(x = 0; x < line_add; x++){
if(block[pBlock->shape][y][x] == 1){
pBlock->dest[i].x = pBlock->left_top_x + x;
pBlock->dest[i].y = pBlock->left_top_y + y;
i++;
}
}
}
/* 选入砖块
* 参数 :pBlock 用于存储选中的砖块的信息
* n 砖块的编号
* m 砖块内的形状编号
*/
int Select_Block(BLOCK_INFO *pBlock, int next_block, int next_shape){
int select;
pBlock->left_top_x = MAX_X / 2 - 2;
pBlock->left_top_y = 1;
pBlock->shape_n = next_block;
pBlock->shape = next_shape;
pBlock->shape_count= shape[next_block];
switch( pBlock->shape_n ){
case 0: Write_Block_Coord(block1, pBlock);
break;
case 1: Write_Block_Coord(block2, pBlock);
break;
case 2: Write_Block_Coord(block3, pBlock);
break;
case 3: Write_Block_Coord(block4, pBlock);
break;
case 4: Write_Block_Coord(block5, pBlock);
break;
case 5: Write_Block_Coord(block6, pBlock);
break;
case 6: Write_Block_Coord(block7, pBlock);
break;
default:printf("Game Error When Select Block !\n");
system("pause");
exit(1);
}
return select;
}
/* 检查砖块是否能向 dest 方向移动 */
int Check_Move(int dest, BLOCK_INFO *pBlock, COORD new_dest[]){
int i;
switch( dest ){
case COMMON_DOWN:
case QUICK_DOWN:
for(i = 0; i < 4; i++){
if( metrix[pBlock->dest[i].y+1][pBlock->dest[i].x] ||
pBlock->dest[i].y+1 >= MAX_Y )
return !OK;
new_dest[i].x = pBlock->dest[i].x;
new_dest[i].y = pBlock->dest[i].y + 1;
}
pBlock -> left_top_y++;
return OK;
case LEFT: for(i = 0; i < 4; i++){
if( metrix[pBlock->dest[i].y][pBlock->dest[i].x-1] ||
pBlock->dest[i].x-1 <= 0 )
return !OK;
new_dest[i].x = pBlock->dest[i].x - 1;
new_dest[i].y = pBlock->dest[i].y;
}
pBlock -> left_top_x--;
return OK;
case RIGHT: for(i = 0; i < 4; i++){
if( metrix[pBlock->dest[i].y][pBlock->dest[i].x+1] ||
pBlock->dest[i].x+1 >= MAX_X )
return !OK;
new_dest[i].x = pBlock->dest[i].x + 1;
new_dest[i].y = pBlock->dest[i].y;
}
pBlock -> left_top_x++;
return OK;
default: return OK;
}
}
/* 屏幕显示砖块
* 参数:dest 记录屏幕打印位置
*/
void Show_Block(COORD dest[]){
int i;
for(i = 0; i < 4; i++){
gotoxy(dest[i].x, dest[i].y);
putchar(block_char);
}
}
/* 检查是否命中一行, 如果命中则更新 level, score */
void Test_GetLine(void){
int flag, x, y;
char *p_dest,*p_sour;
for(y = 4; y < MAX_Y; y++){
for(flag = x = 1; x < MAX_X; x++){
if(metrix[y][x] ==0){
flag = 0;
break;
}
}
if(flag == 1){
gettext(edge_left+1,edge_top+2,edge_right-1,edge_top+y-1,video);
puttext(edge_left+1,edge_top+3,edge_right-1,edge_top+y,video);
p_dest = &metrix[y][MAX_X-1];
p_sour = p_dest - MAX_X;
for(; p_sour != (char*)metrix; p_dest--, p_sour--)
*p_dest = *p_sour;
score += 100;
if(score >= 500 * level){
speed -= ADD_SPEED;
level++;
putchar(BELL);
}
Update_Level_Score();
}
}
}
/* 更新大矩阵,即屏幕上的游戏区域 */
int Update_Metrix(BLOCK_INFO *pBlock){
int i,x,y;
for(i = 0; i < 4; i++){
if(metrix[pBlock->dest[i].y][pBlock->dest[i].x])
return !OK;
metrix[pBlock->dest[i].y][pBlock->dest[i].x] = 1;
}
Test_GetLine();
return OK;
}
/* 移动砖块到 new_dest 位置 */
void Move_Block(COORD new_dest[],BLOCK_INFO *pBlock){
int i;
for(i = 0; i < 4; i++){
gotoxy(pBlock->dest[i].x, pBlock->dest[i].y);
putchar(' ');
pBlock->dest[i].x = new_dest[i].x;
pBlock->dest[i].y = new_dest[i].y;
}
Show_Block(pBlock->dest);
delay(speed);
}
/* 动态的游戏结束画面 */
void Print_Over(char c, int y){
int x;
for(x = 1; x < MAX_X; x++){
gotoxy(x,y);
putchar(c);
}
delay(50);
}
/* 等待按开始键开始游戏 */
void Wait_Start(void){
int key;
putchar(BELL);
do{
key = bioskey(0);
}while(key != ENTER && key != ESC);
if(key == ESC)
exit(0);
}
/* 游戏结束,显示结束画面 */
void Show_GameOver(void){
int x,y;
for(y = MAX_Y - 1; y > 0; y--)
Print_Over(block_char,y);
for(y = 1; y < MAX_Y; y++)
Print_Over(' ',y);
window(edge_left+1, edge_top+4, edge_right-1, edge_top+8);
textattr(BLINK+WHITE+(RED<<4));
clrscr();
gotoxy(1,2); printf(" Game ");
gotoxy(1,3); printf(" Over");
gotoxy(1,4); printf(" !!! ");
putchar(BELL) ;
Wait_Start();
window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
textcolor(YELLOW);
Init_Face_Block(BLACK);
}
/* 获取砖块的相对坐标--在矩阵 metrix 中的位置
* 参数说明:pBkSp 用于临时存储砖块变形后的相关信息
* pBlock 当前砖块的有关信息
*/
void Get_New_Shape(BLOCK_INFO *pBkSp, BLOCK_INFO *pBlock){
int x, y;
if(pBlock->shape+1 < pBlock->shape_count)
pBkSp->shape = pBlock->shape + 1;
else
pBkSp->shape = 0;
pBkSp->left_top_x = pBlock->left_top_x;
pBkSp->left_top_y = pBlock->left_top_y;
pBkSp->shape_n = pBlock->shape_n;
switch( pBlock->shape_n ){
case 0: Write_Block_Coord(block1, pBkSp);
break;
case 1: Write_Block_Coord(block2, pBkSp);
break;
case 2: Write_Block_Coord(block3, pBkSp);
break;
case 3: Write_Block_Coord(block4, pBkSp);
break;
case 4: Write_Block_Coord(block5, pBkSp);
break;
case 5: Write_Block_Coord(block6, pBkSp);
break;
case 6: Write_Block_Coord(block7, pBkSp);
break;
default:printf("Game Error When Change Block Shape !\n");
system("pause");
exit(1);
}
}
/* 砖块变形 */
void Change_Shape(BLOCK_INFO *pBlock){
int i, x, y, line_add = 3;
BLOCK_INFO temp;
if(pBlock -> shape_count == 1)
return ;
else if(pBlock->shape_n == 0)
line_add = 4;
for(y = pBlock->left_top_y; y < pBlock->left_top_y + line_add; y++)
for(x = pBlock->left_top_x; x < pBlock->left_top_x + line_add; x++){
if(metrix[y][x] || y >= MAX_Y || x < 1 || x >= MAX_X)
return ;
}
Get_New_Shape(&temp, pBlock);
Move_Block(temp.dest,pBlock);
pBlock->shape = temp.shape;
for(i = 0; i < 4; i++){
pBlock->dest[i].x = temp.dest[i].x;
pBlock->dest[i].y = temp.dest[i].y;
}
}
/* 显示下一个砖块 */
void Print_Next_Block(BLOCK_INFO *pBlock){
COORD temp[4];
int i;
for(i = 0; i < 4; i++){
temp[i].x = pBlock->dest[i].x - pBlock->left_top_x + 2;
temp[i].y = pBlock->dest[i].y - pBlock->left_top_y + 2;
}
window(edge_right+4, edge_top-5, edge_right+10, edge_top-1);
clrscr();
Show_Block(temp);
window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
}
int main(void){
int dest, key, flag, speed_save;
int next_block, next_shape;
COORD new_dest[4];
BLOCK_INFO block_info,block_info_next;
/* system("full"); 注意找到 full.exe 放到 TC.exe 同目录下,进入全屏模式 */
Configure_Game();
Hide_Cursor();
Init_Face();
Init_Game();
Select_Block(&block_info_next, 0, 0);
Print_Next_Block(&block_info_next);
Wait_Start();
for(flag = 0 ;; ){
if(flag == 0){
memcpy(&block_info, &block_info_next, sizeof(BLOCK_INFO));
next_block = rand() % BLOCK_COUNT;
next_shape = rand() % shape[next_block];
Select_Block(&block_info_next, next_block, next_shape);
Print_Next_Block(&block_info_next);
Show_Block(block_info.dest);
flag = 1;
}
if(!kbhit())
dest = COMMON_DOWN;
else{
key = bioskey( 0 );
switch( key ){
case QUICK_DOWN:
dest = QUICK_DOWN;
break;
case LEFT: dest = LEFT;
break;
case RIGHT: dest = RIGHT;
break;
case UP: Change_Shape(&block_info);
continue;
case ENTER: Wait_Start();
break;
case ESC: return 0;
default: dest = COMMON_DOWN;
break;
}
}
if(Check_Move(dest, &block_info, new_dest) != OK){
if(dest == COMMON_DOWN || dest == QUICK_DOWN){
if(Update_Metrix(&block_info) != OK){
Show_GameOver();
Init_Game();
}
flag = 0;
}
}
else if(dest == QUICK_DOWN){
speed_save = speed;
speed = ADD_SPEED * 3;
Move_Block(new_dest, &block_info);
if(Check_Move(dest, &block_info, new_dest) == OK)
Move_Block(new_dest, &block_info);
speed = speed_save - ADD_SPEED * 3 + speed;
}
else
Move_Block(new_dest, &block_info);
}
}
评论