返回目录:游戏解答
(1)第一个cpp:
#include "colorConsole.h"
HANDLE initiate()
{
HANDLE hOutput;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
return hOutput;
}
BOOL textout(HANDLE hOutput,int x,int y,WORD wColors[],int nColors,LPTSTR lpszString)
{
DWORD cWritten;
BOOL fSuccess;
COORD coord;
coord.X = x; // start at first cell
coord.Y = y; // of first row
fSuccess = WriteConsoleOutputCharacter(
hOutput, // screen buffer handle
lpszString, // pointer to source string
lstrlen(lpszString), // length of string
coord, // first cell to write to
&cWritten); // actual number written
if (! fSuccess)
cout<<"error:WriteConsoleOutputCharacter"<<endl;
for (;fSuccess && coord.X < lstrlen(lpszString)+x; coord.X += nColors)
{
fSuccess = WriteConsoleOutputAttribute(
hOutput, // screen buffer handle
wColors, // pointer to source string
nColors, // length of string
coord, // first cell to write to
&cWritten); // actual number written
}
if (! fSuccess)
cout<<"error:WriteConsoleOutputAttribute"<<endl;
return 0;
}
(2)第二个cpp
#include <conio.h>
#include <stdlib.h>
#include<stdio.h>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib") //播放背景音乐的头文件
#include "colorConsole.h"
#include<time.h>
#define SQUARE_COLOR BACKGROUD_BLUE|BACKGROUD_RED| BACKGROUD_INTENSITY //背景颜色
#define SQUARE_COLOR FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY //方块的颜色
#define up 72
#define down 80
#define left 75
#define right 77
#define esc 27
#define MAPW 15 //地图的宽度
#define MAPH 25 //地图的高度
void initiate1();
int * build(); //创建方块 7a64e78988e69d83336 //初始化工作
BOOL isavailable(int a[],int x,int y,int w,int h); //判定是否能放下
void drawblocks(int a[],int w,int h,int x,int y,WORD wColors[],int nColors);
void delete_cache(); //清除键盘缓冲区
void revolve(int a[][4],int w,int h,int *x,int y); //转动方块
void pro();
void end();
void delete_blocks(int *a,int w,int h,int x,int y);
void gameover();
void deletefull_line(int m[][MAPW],int row,int w,int h); //消除一行
int dx=30,dy=5; //屏幕上的偏移量
int score=0,level=0;
int map[MAPH][MAPW];
int a1[4][4]={{1},{1,1,1}};
int a2[4][4]={{0,1},{1,1,1}};
int a3[4][4]={{1,1},{0,1,1}};
int a4[4][4]={{0,0,1},{1,1,1}};
int a5[4][4]={{0,1,1},{1,1}};
int a6[4][4]={{1,1,1,1}};
int a7[4][4]={{1,1},{1,1}};
int a[4][4];
int main()
{
HANDLE handle;
handle=initiate();
WORD wColors[1]={FOREGROUND_BLUE| FOREGROUND_GREEN|FOREGROUND_INTENSITY };
while(1)
{
sndPlaySound("Resource\\Just Dance.wav",SND_LOOP|SND_ASYNC);//用异步方式播放音乐,PlaySound函数在开始播放后立即返回
system("CLS");
int n=0;
printf("目录\n1.开始游戏\n2.退出游戏\n\n\n");
scanf("%d",&n);
switch(n)
{
case 1:
system("CLS");
textout(handle,22,6,wColors+2,1,"请选择游戏等级:");
textout(handle,32,8,wColors+2,1,"1.初级");
textout(handle,32,10,wColors+2,1,"2.中级");
textout(handle,32,12,wColors+2,1,"3.高级");
while(1)
{
char choice;
choice=_getch();
if(choice=='1')
{
textout(handle,22,6,wColors+2,1,"开始游戏,初级");
textout(handle,32,8,wColors+2,1," ");
textout(handle,32,10,wColors+2,1," ");
textout(handle,32,12,wColors+2,1," ");
level=0,score=0;
Sleep(2000);
textout(handle,22,6,wColors+2,1," ");
break;
}
else if(choice=='2')
{
textout(handle,22,6,wColors+2,1,"开始游戏,中级");
textout(handle,32,8,wColors+2,1," ");
textout(handle,32,10,wColors+2,1," ");
textout(handle,32,12,wColors+2,1," ");
level=2,score=20;
Sleep(2000);
textout(handle,22,6,wColors+2,1," ");
break;
}
else if(choice=='3')
{
textout(handle,22,6,wColors+2,1,"开始游戏,高级");
textout(handle,32,8,wColors+2,1," ");
textout(handle,32,10,wColors+2,1," ");
textout(handle,32,12,wColors+2,1," ");
level=4,score=40;
Sleep(2000);
textout(handle,22,6,wColors+2,1," ");
break;
}
else if(choice!='1'&&choice!='2'&&choice!='3')
continue;
}
pro();
break;
case 2:
return 0;
default:
printf("错误,按键继续");
while(!_kbhit());
}
}
}
void pro() //游戏主题
{
initiate1();
int *b=NULL;
b=build(); //创建方块
int sign,blank,x,y;
while(1)
{
for(int i=0;i<4;i++) //复制方块
for(int j=0;j<4;j++)
if(a[i][j]=*(b+i*4+j)) blank=i;
y=1-blank;x=4;
delete_blocks(&a[0][0],4,4,16,10);
b=build();
HANDLE handle;
handle=initiate();
WORD wColors[1]={FOREGROUND_BLUE| FOREGROUND_GREEN|FOREGROUND_INTENSITY };
drawblocks(b,4,4,16,10,wColors,1);
wColors[0]=SQUARE_COLOR;
drawblocks(&a[0][0],4,4,x,y,wColors,1);
delete_cache();
char string[5];
wColors[0]=FOREGROUND_RED| FOREGROUND_GREEN|FOREGROUND_INTENSITY;
textout(handle,dx-10,8+dy,wColors,1,itoa(score,string,10));
textout(handle,dx-10,14+dy,wColors,1,itoa(level,string,10));
sign=1;
while(sign)
{
int delay=0,max_delay=100-10*level; //延迟量
while(delay<max_delay)
{
if(_kbhit()) //用if避免按住键使方块卡住
{
int draw=0;
int key=_getch();
switch (key)
{
case up:
delete_blocks(&a[0][0],4,4,x,y);
revolve(a,4,4,&x,y);
draw=1;
break;
case down:
delay=max_delay;
break;
case left:
if(isavailable(&a[0][0],x-1,y,4,4))
{
delete_blocks(&a[0][0],4,4,x,y);
x--;
draw=1;
}
break;
case right:
if(isavailable(&a[0][0],x+1,y,4,4))
{
delete_blocks(&a[0][0],4,4,x,y);
x++;
draw=1;
}
break;
case 32://32 是空格键的ASCII码,按空格键暂停
while(1)
{
textout(handle,dx,-2+dy,wColors,1,"Press any key to continue");
Sleep(200);
textout(handle,dx,-2+dy,wColors,1," ");
Sleep(200);
if(_kbhit())
{
draw=1;
break;
}
}
break;
case esc://按键退出游戏
exit(EXIT_SUCCESS);
}
if(draw)
{
HANDLE handle;
handle=initiate();
WORD wColors[1]={SQUARE_COLOR};
drawblocks(&a[0][0],4,4,x,y,wColors,1);
draw=0;
}
}
_sleep(5);delay++;
}
if(isavailable(&a[0][0],x,y+1,4,4)) //是否能下移
{
delete_blocks(&a[0][0],4,4,x,y);
y++;
HANDLE handle;
handle=initiate();
WORD wColors[1]={SQUARE_COLOR};
drawblocks(&a[0][0],4,4,x,y,wColors,1);
}
else
{
sign=0; //标记,使跳出 while(sign) 循环,产生新方块
if(y<=1)
{
system("CLS");
HANDLE handle;
handle=initiate();
WORD wColors[1]={FOREGROUND_RED| FOREGROUND_GREEN};
textout(handle,4+dx,6+dy,wColors,1,"GAME OVER!!!");
textout(handle,4+dx,8+dy,wColors,1,"分数:");
textout(handle,10+dx,8+dy,wColors,1,itoa(score,string,10));
textout(handle,4+dx,10+dy,wColors,1,"制作者:***");
delete_cache();
exit(EXIT_SUCCESS);
} //是否结束
for(int i=0;i<4;i++) //放下方块
for(int j=0;j<4;j++)
if(a[i][j]&&((i+y)<MAPH-1)&&((j+x)<MAPW-1))
map[i+y][j+x]=a[i][j];
int full,k=0;
for( i=y;i<min(y+4,MAPH-1);i++)
{
full=1;
for(int j=1;j<14;j++)
if(!map[i][j]) full=0;
if(full) //消掉一行
{
deletefull_line(map,i,MAPW,MAPH);
k++;
score=score+k;
level=min(score/10,9);
}
}
}
}
}
}
void initiate1() //初始化
{
int i;
for(i=0;i<25;i++)
{
map[i][0]=-2;
map[i][14]=-2;
}
for(i=0;i<15;i++)
{
map[0][i]=-1;
map[24][i]=-1;
}
map[0][0]=-3;
map[0][14]=-3;
map[24][0]=-3;
map[24][14]=-3;
HANDLE handle;
handle=initiate();
WORD wColors[1]={FOREGROUND_GREEN| FOREGROUND_BLUE|FOREGROUND_INTENSITY};
textout(handle,dx-10,6+dy,wColors,1,"SCORE");
textout(handle,dx-10,12+dy,wColors,1,"LEVEL");
textout(handle,32+dx,8+dy,wColors,1,"NEXT");
wColors[0]=FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY;
drawblocks(&map[0][0],15,25,0,0,wColors,1);
textout(handle,dx,dy,wColors,1,"◎═════════════◎");
wColors[0]=FOREGROUND_BLUE| FOREGROUND_GREEN|FOREGROUND_INTENSITY;
textout(handle,dx+8,dy+5,wColors,1,"按任意键开始");
wColors[0]=FOREGROUND_BLUE|FOREGROUND_RED|FOREGROUND_INTENSITY ;
textout(handle,dx+7,dy-3,wColors,1,"制作者:***");
int x=_getch();
srand(time(NULL));
textout(handle,dx+8,dy+5,wColors,1," ");
}
int * build() //创建方块
{
int * a=NULL;
int c=rand()%7;
switch(c)
{
case 0:
a=&a1[0][0];break;
case 1:
a=&a2[0][0];break;
case 2:
a=&a3[0][0];break;
case 3:
a=&a4[0][0];break;
case 4:
a=&a5[0][0];break;
case 5:
a=&a6[0][0];break;
case 6:
a=&a7[0][0];break;
}
return a;
}
void drawblocks(int a[],int w,int h,int x,int y,WORD wColors[],int nColors) //画出方块
{
HANDLE handle;
handle = initiate();
int temp;
for(int i=0;i<h;i++)
for(int j=0;j<w;j++)
if((temp=a[i*w+j])&&y+i>0)
{
if(temp==-3)
{
textout(handle,2*(x+j)+dx,y+i+dy,wColors,nColors,"◎");
_sleep(30);
}
else if(temp==-2)
{
textout(handle,2*(x+j)+dx,y+i+dy,wColors,nColors,"║");
_sleep(30);
}
else if(temp==1)
textout(handle,2*(x+j)+dx,y+i+dy,wColors,nColors,"◎");
else if(temp==-1)
{
textout(handle,2*(x+j)+dx,y+i+dy,wColors,nColors,"═");
_sleep(30);
}
}
}
void delete_cache() //清除缓冲区
{
while(_kbhit())
{
_getch();
}
}
void delete_blocks(int *a,int w,int h,int x,int y) //覆盖方块
{
HANDLE handle;
handle=initiate();
WORD wColors[1]={SQUARE_COLOR};
for(int i=0;i<h;i++)
for(int j=0;j<w;j++)
if(a[i*w+j]&&i+y>0)
textout(handle,2*(x+j)+dx,y+i+dy,wColors,1," ");
}
void revolve(int a[][4],int w,int h,int *x,int y) //转动方块
{
int b[4][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
int sign=0,line=0;
for(int i=h-1;i>=0;i--)
{
for(int j=0;j<w;j++)
if(a[i][j])
{
b[j][line]=a[i][j];
sign=1;
}
if(sign)
{
line++;
sign=0;
}
}
for(i=0;i<4;i++)
if(isavailable(&b[0][0],*x-i,y,w,h))
{
*x-=i;
for(int k=0;k<h;k++)
for(int j=0;j<w;j++)
a[k][j]=b[k][j];
break;
}
}
void deletefull_line(int m[][MAPW],int row,int w,int h) //消除满行的方块
{
HANDLE handle;
handle=initiate();
WORD wColors[1]={SQUARE_COLOR};
textout(handle,2+dx,row+dy,wColors,1,"﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌");
_sleep(100);
int i;
for(i=row;i>1;i--)
{
delete_blocks(&m[i][1],MAPW-2,1,1,i);
for(int j=1;j<MAPW-1;j++)
m[i][j]=m[i-1][j];
drawblocks(&m[i][1],MAPW-2,1,1,i,wColors,1);
}
for(i=1;i<MAPW-1;i++)
m[1][i]=0;
}
BOOL isavailable(int a[],int x,int y,int w,int h)
{
for(int i=max(y,1);i<y+h;i++)
for(int j=x;j<x+w;j++)
if(map[i][j]&&a[w*(i-y)+j-x])
return 0;
return 1;
}
俄罗斯方块C源代码
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define ZL 4 //坐标增量, 不使游戏窗口靠边
#define WID 36 //游戏窗口的宽度
#define HEI 20 //游戏窗口的高度
int i,j,Ta,Tb,Tc; // Ta,Tb,Tc用于记住和转换方块变量的值
int a[60][60]={0}; //标记游戏屏幕各坐标点:0,1,2分别为空、方块、边框
int b[4]; //标记4个"口"方块:1有,0无,类似开关
int x,y, level,score,speed; //方块中心位置的x,y坐标,游戏等级、得分和游戏速度
int flag,next; //当前要操作的方块类型序号,下一个方块类型序号
void gtxy(int m, int n); //以下声明要用到的自编函数
void gflag( ); //获得下一方块序号
void csh( ); //初始化界面
void start( ); //开始部分
void prfk ( ); //打印方块
void clfk( ); //清除方块
void mkfk( ); //制作方块
void keyD( ); //按键操作
int ifmov( ); //判断方块能否移动或变体
void clHA( ); //清除满行的方块
void clNEXT( ); //清除边框外的NEXT方块
int main( )
{ csh( );
while(1)
{start( ); //开始部分
while(1)
{ prfk( );
Sleep(speed); //延时
clfk( );
Tb=x;Tc=flag; //临存当前x坐标和序号,以备撤销操作
keyD( );
y++; //方块向下移动
if (ifmov( )==0) { y--; prfk( ); dlHA( ); break;} //不可动放下,删行,跨出循环
}
for(i=y-2;i<y+2;i++){ if (i==ZL) { j=0; } } //方块触到框顶
if (j==0) { system("cls");gtxy(10,10);printf("游戏结束!"); getch(); break; }
clNEXT( ); //清除框外的NEXT方块
}
return 0;
}
void gtxy(int m, int n) //控制光标移动
{COORD pos; //定义变量
pos.X = m; //横坐标
pos.Y = n; //纵坐标
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void csh( ) //初始化界面
{gtxy(ZL+WID/2-5,ZL-2); printf("俄罗斯方块"); //打印游戏名称
gtxy(ZL+WID+3,ZL+7); printf("******* NEXT:"); //打印菜单信息
gtxy(ZL+WID+3,ZL+13); printf("**********");
gtxy(ZL+WID+3,ZL+15); printf("Esc :退出游戏");
gtxy(ZL+WID+3,ZL+17); printf("↑键:变体");
gtxy(ZL+WID+3,ZL+19); printf("空格:暂停游戏");
gtxy(ZL,ZL); printf("╔"); gtxy(ZL+WID-2,ZL); printf("╗"); //打印框角
gtxy(ZL,ZL+HEI); printf("╚"); gtxy(ZL+WID-2,ZL+HEI); printf("╝");
a[ZL][ZL+HEI]=2; a[ZL+WID-2][ZL+HEI]=2; //记住有图案
for(i=2;i<WID-2;i+=2) {gtxy(ZL+i,ZL); printf("═"); } //打印上横框
for(i=2;i<WID-2;i+=2) {gtxy(ZL+i,ZL+HEI); printf("═"); a[ZL+i][ZL+HEI]=2; } //下框
for(i=1;i<HEI;i++) { gtxy(ZL,ZL+i); printf("║"); a[ZL][ZL+i]=2; } //左竖框记住有图案
for(i=1;i<HEI;i++) {gtxy(ZL+WID-2,ZL+i); printf("║"); a[ZL+WID-2][ZL+i]=2; } //右框
CONSOLE_CURSOR_INFO cursor_info={1,0}; //以下是隐藏光标的设置
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
level=1; score=0; speed=400;
gflag( ); flag=next; //获得一个当前方块序号
}
void gflag( ) //获得下一个方块的序号
{ srand((unsigned)time(NULL)); next = rand()%19+1; }
void start( ) //开始部分
{ gflag( ); Ta=flag; flag=next; //保存当前方块序号,将下一方块序号临时操作
x=ZL+WID+6; y=ZL+10; prfk( ); //给x,y赋值,在框外打印出下一方块
flag=Ta; x=ZL+WID/2; y=ZL-1; //取回当前方块序号,并给x,y赋值
}
void prfk ( ) //打印俄罗斯方块
{ for(i=0;i<4;i++) {b[i]=1; } //数组b[4]每个元素的值都为1
mkfk ( ); //制作俄罗斯方块
for( i= x-2; i<=x+4; i+=2 ) //打印方块
{ for(j=y-2;j<= y+1;j++) { if( a[i][j]==1 && j>ZL ){ gtxy(i,j); printf("□"); } } }
gtxy(ZL+WID+3,ZL+1); printf("level : %d",level); //以下打印菜单信息
gtxy(ZL+WID+3,ZL+3); printf("score : %d",score);
gtxy(ZL+WID+3,ZL+5); printf("speed : %d",speed);
}
void clfk( ) //清除俄罗斯方块
{ for(i=0;i<4;i++) { b[i]=0; } //数组b[4]每个元素的值都为0
mkfk ( ); //制作俄罗斯方块
for( i=x-2; i<=x+4; i+=2 ) //清除方块
{ for(j=y-2;j<=y+1;j++){ if( a[i][j]==0 && j>ZL ){ gtxy(i,j); printf(" "); } } }
}
void mkfk( ) //制作俄罗斯方块
{ a[x][ y]=b[0]; //方块中心位置状态: 1-有,0-无
switch(flag) //共6大类,19种小类型
{ case 1: { a[x][y-1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //田字方块
case 2: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x+4][y]=b[3]; break; } //直线方块:----
case 3: { a[x][y-1]=b[1]; a[x][y-2]=b[2]; a[x][y+1]=b[3]; break; } //直线方块: |
case 4: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x][y+1]=b[3]; break; } //T字方块
case 5: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y]=b[3]; break; } //T字顺时针转90度
case 6: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x+2][y]=b[3]; break; } //T字顺转180度
case 7: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y]=b[3]; break; } //T字顺转270度
case 8: { a[x][y+1]=b[1]; a[x-2][y]=b[2]; a[x+2][y+1]=b[3]; break; } //Z字方块
case 9: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x-2][y+1]=b[3]; break; } //Z字顺转90度
case 10: { a[x][y-1]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //Z字顺转180度
case 11: { a[x][y+1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][ y]=b[3]; break; } //Z字顺转270度
case 12: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y-1]=b[3]; break; } //7字方块
case 13: {a[x-2][y]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //7字顺转90度
case 14: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y+1]=b[3]; break; } //7字顺转180度
case 15: { a[x-2][y]=b[1]; a[x-2][y+1]=b[2]; a[x+2][y]=b[3]; break; } //7字顺转270度
case 16: { a[x][y+1]=b[1]; a[x][y-1]=b[2]; a[x+2][y-1]=b[3]; break; } //倒7字方块
case 17: { a[x-2][y]=b[1]; a[x+2][y+1]=b[2]; a[x+2][y]=b[3]; break; } //倒7字顺转90度
case 18: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y+1]=b[3]; break; } //倒7字顺转180度
case 19: { a[x-2][y]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //倒7字顺转270度
}
}
void keyD( ) //按键操作
{ if (kbhit( ))
{ int key;
key=getch();
if (key==224)
{ key=getch();
if (key==75) { x-=2; } //按下左方向键,中心横坐标减2
if (key==77) { x+=2; } //按下右方向键,中心横坐标加2
if (key==72) //按下向上方向键,方块变体
{ if (flag>=2 && flag<=3 ) { flag++; flag%=2; flag+=2; }
if ( flag>=4 && flag<=7 ) { flag++; flag%=4; flag+=4; }
if (flag>=8 && flag<=11 ) { flag++; flag%=4; flag+=8; }
if (flag>=12 && flag<=15 ) { flag++; flag%=4; flag+=12; }
if ( flag>=16 && flag<=19 ) { flag++; flag%=4; flag+=16; } }
}
if (key==32) //按空格键,暂停
{ prfk( ); while(1) { if (getch( )==32) { clfk( );break;} } } //再按空格键,继续游戏
if (ifmov( )==0) { x=Tb; flag=Tc; } //如果不可动,撤销上面操作
else { prfk( ); Sleep(speed); clfk( ); Tb=x;Tc=flag;} //如果可动,执行操作
}
}
int ifmov( ) //判断能否移动
{ if (a[x][y]!=0) { return 0; } //方块中心处有图案返回0,不可移动
else{ if ( (flag==1 && ( a[x][ y-1]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||
(flag==2 && ( a[x-2][y]==0 && a[x+2][y]==0 && a[x+4][y]==0 ) ) ||
(flag==3 && ( a[x][y-1]==0 && a[x][y-2]==0 && a[x][y+1]==0 ) ) ||
(flag==4 && ( a[x-2][y]==0 && a[x+2][y]==0 && a[x][y+1]==0 ) ) ||
(flag==5 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x-2][y]==0 ) ) ||
(flag==6 && ( a[x][ y-1]==0 && a[x-2][y]==0 && a[x+2][y]==0 ) ) ||
(flag==7 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==8 && ( a[x][y+1]==0 && a[x-2][y]==0 && a[x+2][y+1]==0 ) ) ||
(flag==9 && ( a[x][y-1]==0 && a[x-2][y]==0 && a[x-2][y+1]==0 ) ) ||
(flag==10 && ( a[x][y-1]==0 && a[x-2][y-1]==0 && a[x+2][y]==0 ) ) ||
(flag==11 && ( a[x][y+1]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||
(flag==12 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x-2][y-1]==0 ) ) ||
( flag==13 && ( a[x-2][y]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||
( flag==14 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y+1]==0 ) ) ||
(flag==15 && ( a[x-2][y]==0 && a[x-2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==16 && ( a[x][y+1]==0 && a[x][y-1]==0 && a[x+2][y-1]==0 ) ) ||
( flag==17 && ( a[x-2][y]==0 && a[x+2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==18 && ( a[x][y-1]==0 &&a[x][y+1]==0 && a[x-2][y+1]==0 ) ) ||
(flag==19 && ( a[x-2][y]==0 && a[x-2][y-1]==0
&& a[x+2][y]==0 ) ) ) { return 1; }
}
return 0; //其它情况返回0
}
void clNEXT( ) //清除框外的NEXT方块
{ flag = next; x=ZL+WID+6; y=ZL+10; clfk( ); }
void clHA( ) //清除满行的方块
{ int k, Hang=0; //k是某行方块个数, Hang是删除的方块行数
for(j=ZL+HEI-1;j>=ZL+1;j--) //当某行有WID/2-2个方块时,则为满行
{ k=0; for(i=ZL+2;i<ZL+WID-2;i+=2)
{ if (a[i][j]==1) //竖坐标从下往上,横坐标由左至右依次判636f7079e79fa5e98193337断是否满行
{ k++; //下面将操作删除行
if (k==WID/2-2) { for(k=ZL+2;k<ZL+WID-2;k+=2)
{ a[k][j]=0; gtxy(k,j); printf(" "); Sleep(1); }
for(k=j-1;k>ZL;k--)
{ for(i=ZL+2;i<ZL+WID-2;i+=2) //已删行数上面有方块,先清除再全部下移一行
{ if(a[i][k]==1) { a[i][k]=0; gtxy(i,k); printf(" ");a[i][k+1]=1;
gtxy(i,k+1); printf("□"); } }
}
j++; //方块下移后,重新判断删除行是否满行
Hang++; //记录删除方块的行数
}
}
}
}
score+=100*Hang; //每删除一行,得100分
if ( Hang>0 && (score%500==0 || score/500> level-1 ) ) //得分满500速度加快升一级
{ speed-=20; level++; if(speed<200)speed+=20; }
}
(1)由于c的随机性函数不好,所以每次游戏开始根据bios时间设置种子。
(2)得分越高,方块下降速度越快(每200分为单位)。
(3)每下落一个方块加1分,每消除一行加10分,两行加30分,三行加70分,四行加150分。初试分数为100分。
游戏控制:
up-旋转;空格-下落到底; 左右下方向键-控制方向。P-开始或暂停游戏。 ESC-退出。
特点:
(1)由于tc不支持中文,所以基本都是英文注释。
(2)函数命名尽可能规范的表达其内部处理目的和过程。
(3)代码加上注释仅有577行。(我下载过的两个俄罗斯方块代码一个在1087行,一个在993行,我的比它们代码少)。
(4)除了消除空格时算法比较复杂,其他算法都比较简单易读。
(5)绘图效率和局部代码效率扔有待提高。
(6)FrameTime参数可能依据不同硬件环境进行具体设置,InitGame需要正确的TC路径。
/********************************/
/* Desc: 俄罗斯方块游戏 */
/* By: hoodlum1980 */
/* Email: */
/* Date: 2008.03.12 22:30 */
/********************************/
#include <stdio.h>
#include <bios.h>
#include <dos.h>
#include <graphics.h>
#include <string.h>
#include <stdlib.h>
#define true 1
#define false 0
#define BoardWidth 12
#define BoardHeight 23
#define _INNER_HELPER /*inner helper method */
/*Scan Codes Define*/
enum KEYCODES
{
K_ESC =0x011b,
K_UP =0x4800, /* upward arrow */
K_LEFT =0x4b00,
K_DOWN =0x5000,
K_RIGHT =0x4d00,
K_SPACE =0x3920,
K_P =0x1970
};
/* the data structure of the block */
typedef struct tagBlock
{
char c[4][4]; /* cell fill info array, 0-empty, 1-filled */
int x; /* block position cx [ 0,BoardWidht -1] */
int y; /* block position cy [-4,BoardHeight-1] */
char color; /* block color */
char size; /* block max size in width or height */
char name; /* block name (the block's shape) */
} Block;
/* game's global info */
int FrameTime= 1300;
int CellSize= 18;
int BoardLeft= 30;
int BoardTop= 30;
/* next block grid */
int NBBoardLeft= 300;
int NBBoardTop= 30;
int NBCellSize= 10;
/* score board position */
int ScoreBoardLeft= 300;
int ScoreBoardTop=100;
int ScoreBoardWidth=200;
int ScoreBoardHeight=35;
int ScoreColor=LIGHTCYAN;
/* infor text postion */
int InfoLeft=300;
int InfoTop=200;
int InfoColor=YELLOW;
int BorderColor=DARKGRAY;
int BkGndColor=BLACK;
int GameRunning=true;
int TopLine=BoardHeight-1; /* top empty line */
int TotalScore=100;
char info_score[20];
char info_help[255];
char info_common[255];
/* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */
unsigned char Board[BoardWidth][BoardHeight][2];
char BufferCells[4][4]; /* used to judge if can rotate block */
Block curBlock; /* current moving block */
Block nextBlock; /* next Block to appear */
/* function list */
int GetKeyCode();
int CanMove(int dx,int dy);
int CanRotate();
int RotateBlock(Block *block);
int MoveBlock(Block *block,int dx,int dy);
void DrawBlock(Block *block,int,int,int);
void EraseBlock(Block *block,int,int,int);
void DisplayScore();
void DisplayInfo(char* text);
void GenerateBlock(Block *block);
void NextBlock();
void InitGame();
int PauseGame();
void QuitGame();
/*Get Key Code */
int GetKeyCode()
{
int key=0;
if(bioskey(1))
{
key=bioskey(0);
}
return key;
}
/* display text! */
void DisplayInfo(char *text)
{
setcolor(BkGndColor);
outtextxy(InfoLeft,InfoTop,info_common);
strcpy(info_common,text);
setcolor(InfoColor);
outtextxy(InfoLeft,InfoTop,info_common);
}
/* create a new block by key number,
* the block anchor to the top-left corner of 4*4 cells
*/
void _INNER_HELPER GenerateBlock(Block *block)
{
int key=(random(13)*random(17)+random(1000)+random(3000))%7;
block->size=3;/* because most blocks' size=3 */
memset(block->c,0,16);
switch(key)
{
case 0:
block->name='T';
block->color=RED;
block->c[1][0]=1;
block->c[1][1]=1, block->c[2][1]=1;
block->c[1][2]=1;
break;
case 1:
block->name='L';
block->color=YELLOW;
block->c[1][0]=1;
block->c[1][1]=1;
block->c[1][2]=1, block->c[2][2]=1;
break;
case 2:
block->name='J';
block->color=LIGHTGRAY;
block->c[1][0]=1;
block->c[1][1]=1;
block->c[1][2]=1, block->c[0][2]=1;
break;
case 3:
block->name='z';
block->color=CYAN;
block->c[0][0]=1, block->c[1][0]=1;
block->c[1][1]=1, block->c[2][1]=1;
break;
case 4:
block->name='5';
block->color=LIGHTBLUE;
block->c[1][0]=1, block->c[2][0]=1;
block->c[0][1]=1, block->c[1][1]=1;
break;
case 5:
block->name='o';
block->color=BLUE;
block->size=2;
block->c[0][0]=1, block->c[1][0]=1;
block->c[0][1]=1, block->c[1][1]=1;
break;
case 6:
block->name='I';
block->color=GREEN;
block->size=4;
block->c[1][0]=1;
block->c[1][1]=1;
block->c[1][2]=1;
block->c[1][3]=1;
break;
}
}
/* get next block! */
void NextBlock()
{
/* copy the nextBlock to curBlock */
curBlock.size=nextBlock.size;
curBlock.color=nextBlock.color;
curBlock.x=(BoardWidth-4)/2;
curBlock.y=-curBlock.size;
memcpy(curBlock.c,nextBlock.c,16);
/* generate nextBlock and show it */
EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
GenerateBlock(&nextBlock);
nextBlock.x=1,nextBlock.y=0;
DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);
}
/* rotate the block, update the block struct data */
int _INNER_HELPER RotateCells(char c[4][4],char blockSize)
{
char temp,i,j;
switch(blockSize)
{
case 3:
temp=c[0][0];
c[0][0]=c[2][0], c[2][0]=c[2][2], c[2][2]=c[0][2], c[0][2]=temp;
temp=c[0][1];
c[0][1]=c[1][0], c[1][0]=c[2][1], c[2][1]=c[1][2], c[1][2]=temp;
break;
case 4: /* only 'I' block arived here! */
c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3];
c[0][1]=1-c[0][1], c[2][1]=1-c[2][1], c[3][1]=1-c[3][1];
break;
}
}
/* judge if the block can move toward the direction */
int CanMove(int dx,int dy)
{
int i,j,tempX,tempY;
for(i=0;i<curBlock.size;i++)
{
for(j=0;j<curBlock.size;j++)
{
if(curBlock.c[i][j])
{
/* cannot move leftward or rightward */
tempX = curBlock.x + i + dx;
if(tempX<0 || tempX>(BoardWidth-1)) return false; /* make sure x is valid! */
/* cannot move downward */
tempY = curBlock.y + j + dy;
if(tempY>(BoardHeight-1)) return false; /* y is only checked lower bound, maybe negative!!!! */
/* the cell already filled, we must check Y's upper bound before check cell ! */
if(tempY>=0 && Board[tempX][tempY][0]) return false;
}
}
}
return true;
}
/* judge if the block can rotate */
int CanRotate()
{
int i,j,tempX,tempY;
/* update buffer */
memcpy(BufferCells, curBlock.c, 16);
RotateCells(BufferCells,curBlock.size);
for(i=0;i<curBlock.size;i++)
{
for(j=0;j<curBlock.size;j++)
{
if(BufferCells[i][j])
{
tempX=curBlock.x+i;
tempY=curBlock.y+j;
if(tempX<0 || tempX>(BoardWidth-1))
return false;
if(tempY>(BoardHeight-1))
return false;
if(tempY>=0 && Board[tempX][tempY][0])
return false;
}
}
}
return true;
}
/* draw the block */
void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
int i,j;
setfillstyle(SOLID_FILL,block->color);
for(i=0;i<block->size;i++)
{
for(j=0;j<block->size;j++)
{
if(block->c[i][j] && (block->y+j)>=0)
{
floodfill(
bdLeft+cellSize*(i+block->x)+cellSize/2,
bdTop+cellSize*(j+block->y)+cellSize/2,
BorderColor);
}
}
}
}
/* Rotate the block, if success, return true */
int RotateBlock(Block *block)
{
char temp,i,j;
int b_success;
if(curBlock.size==2)
return;
if(( b_success=CanRotate()))
{
EraseBlock(block,BoardLeft,BoardTop,CellSize);
memcpy(curBlock.c,BufferCells,16);
DrawBlock(block,BoardLeft,BoardTop,CellSize);
}
return b_success;
}
/* erase a block, only fill the filled cell with background color */
void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
int i,j;
setfillstyle(SOLID_FILL,BkGndColor);
for(i=0;i<block->size;i++)
{
for(j=0;j<block->size;j++)
{
if(block->c[i][j] && (block->y+j>=0))
{
floodfill(
bdLeft+cellSize*(i+block->x)+cellSize/2,
bdTop+cellSize*(j+block->y)+cellSize/2,
BorderColor);
}
}
}
}
/* move by the direction if can, donothing if cannot
* return value: true - success, false - cannot move toward this direction
*/
int MoveBlock(Block *block,int dx,int dy)
{
int b_canmove=CanMove(dx,dy);
if(b_canmove)
{
EraseBlock(block,BoardLeft,BoardTop,CellSize);
curBlock.x+=dx;
curBlock.y+=dy;
DrawBlock(block,BoardLeft,BoardTop,CellSize);
}
return b_canmove;
}
/* drop the block to the bottom! */
int DropBlock(Block *block)
{
EraseBlock(block,BoardLeft,BoardTop,CellSize);
while(CanMove(0,1))
{
curBlock.y++;
}
DrawBlock(block,BoardLeft,BoardTop,CellSize);
return 0;/* return value is assign to the block's alive */
}
/* init the graphics mode, draw the board grid */
void InitGame()
{
int i,j,gdriver=DETECT,gmode;
struct time sysTime;
/* draw board cells */
memset(Board,0,BoardWidth*BoardHeight*2);
memset(nextBlock.c,0,16);
strcpy(info_help,"P: Pause Game. --by hoodlum1980");
initgraph(&gdriver,&gmode,"c:\\tc\\");
setcolor(BorderColor);
for(i=0;i<=BoardWidth;i++)
{
line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize);
}
for(i=0;i<=BoardHeight;i++)
{
line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize);
}
/* draw board outer border rect */
rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4,
BoardLeft+BoardWidth*CellSize+CellSize/4,
BoardTop+BoardHeight*CellSize+CellSize/4);
/* draw next block grids */
for(i=0;i<=4;i++)
{
line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize);
line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize);
}
/* draw score rect */
rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+ScoreBoardHeight);
DisplayScore();
/* set new seed! */
gettime(&sysTime);
srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec);
GenerateBlock(&nextBlock);
NextBlock(); /* create first block */
setcolor(DARKGRAY);
outtextxy(InfoLeft,InfoTop+20,"Up -rotate Space-drop");
outtextxy(InfoLeft,InfoTop+35,"Left-left Right-right");
outtextxy(InfoLeft,InfoTop+50,"Esc -exit");
DisplayInfo(info_help);
}
/* set the isFilled and fillcolor data to the board */
void _INNER_HELPER FillBoardData()
{
int i,j;
for(i=0;i<curBlock.size;i++)
{
for(j=0;j<curBlock.size;j++)
{
if(curBlock.c[i][j] && (curBlock.y+j)>=0)
{
Board[curBlock.x+i][curBlock.y+j][0]=1;
Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color;
}
}
}
}
/* draw one line of the board */
void _INNER_HELPER PaintBoard()
{
int i,j,fillcolor;
for(j=max((TopLine-4),0);j<BoardHeight;j++)
{
for(i=0;i<BoardWidth;i++)
{
fillcolor=Board[i][j][0]? Board[i][j][1]:BkGndColor;
setfillstyle(SOLID_FILL,fillcolor);
floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,BorderColor);
}
}
}
/* check if one line if filled full and increase the totalScore! */
void _INNER_HELPER CheckBoard()
{
int i,j,k,score=10,sum=0,topy,lines=0;
/* we find the top empty line! */
j=topy=BoardHeight-1;
do
{
sum=0;
for(i=0;i< BoardWidth; i++)
{
sum+=Board[i][topy][0];
}
topy--;
} while(sum>0 && topy>0);
/* remove the full filled line (max remove lines count = 4) */
do
{
sum=0;
for(i=0;i< BoardWidth; i++)
sum+=Board[i][j][0];
if(sum==BoardWidth)/* we find this line is full filled, remove it! */
{
/* move the cells data down one line */
for(k=j; k > topy;k--)
{
for(i=0;i<BoardWidth;i++)
{
Board[i][k][0]=Board[i][k-1][0];
Board[i][k][1]=Board[i][k-1][1];
}
}
/*make the top line empty! */
for(i=0;i<BoardWidth;i++)
{
Board[i][topy][0]=0;
Board[i][topy][1]=0;
}
topy++; /* move the topline downward one line! */
lines++; /* lines <=4 */
TotalScore+=score;
score*=2; /* adding: 10, 30, 70, 150 */
}
else
j--;
} while(sum>0 && j>topy && lines<4);
/* speed up the game when score is high, minimum is 400 */
FrameTime=max(1200-100*(TotalScore/200), 400);
TopLine=topy;/* update the top line */
/* if no lines remove, only add 1: */
if(lines==0)
TotalScore++;
}
/* display the score */
void _INNER_HELPER DisplayScore()
{
setcolor(BkGndColor);
outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);
setcolor(ScoreColor);
sprintf(info_score,"Score: %d",TotalScore);
outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);
}
/* we call this function when a block is inactive. */
void UpdateBoard()
{
FillBoardData();
CheckBoard();
PaintBoard();
DisplayScore();
}
/* pause the game, and timer handler stop move down the block! */
int PauseGame()
{
int key=0;
DisplayInfo("Press P to Start or Resume!");
while(key!=K_P && key!=K_ESC)
{
while(!(key=GetKeyCode())){}
}
DisplayInfo(info_help);
return key;
}
/* quit the game and do cleaning work. */
void QuitGame()
{
closegraph();
}
/* the entry point function. */
void main()
{
int i,flag=1,j,key=0,tick=0;
InitGame();
if(PauseGame()==K_ESC)
goto GameOver;
/* wait until a key pressed */
while(key!=K_ESC)
{
/* wait until a key pressed */
while(!(key=GetKeyCode()))
{
tick++;
if(tick>=FrameTime)
{
/* our block has dead! (can't move down), we get next block */
if(!MoveBlock(&curBlock,0,1))
{
UpdateBoard();
NextBlock();
if(!CanMove(0,1))
goto GameOver;
}
tick=0;
}
delay(100);
}
switch(key)
{
case K_LEFT:
MoveBlock(&curBlock,-1,0);
break;
case K_RIGHT:
MoveBlock(&curBlock,1,0);
break;
case K_DOWN:
MoveBlock(&curBlock,0,1);
break;
case K_UP:
RotateBlock(&curBlock);
break;
case K_SPACE:
DropBlock(&curBlock);
break;
case K_P:
PauseGame();
break;
}
}
GameOver:
DisplayInfo("GAME OVER! Press any key to exit!");
getch(); /* wait the user Press any key. */
QuitGame();
}
----------------------------------【代e799bee5baa6e79fa5e98193e78988e69d83339码文件结尾】--------------------------------------------------