#include
#include
#include
//time()
//#include
//#include
#include
//kbhit()
//Author: 赖依 QQ:54142961
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_UP 72
#define KEY_DOWN 80
#define false 0
#define true 1
#define LINENUM 20 //游戏界面高度,20行
typedef struct CPoint
{
int x;
int y;
}CPoint;
//方块信息
typedef struct
{
CPoint point; //一个方块的中心点位置
unsigned char flags;
//其周围8个位的方块有无标志
}BlockInfo;
void GameOver();
void isFull();
void ShowInfo();
void CreateBlock();
void ClearBlock(unsigned short Panel[], BlockInfo
*block);
int BlockCat(unsigned short int Panel[],BlockInfo*);
void MoveBlock(int direction);
void ChangeType();
void BlockDrop();
//现有的26种方块类型
// * * * 1 2 3 0 1
0
// * + * ==>8 + 4 1 + 1
←←←←←←←←←
// * * * 7 6 5 0 0 0
↑
//一个方块,中间的+是中心点,必然有方块 ↑
//上图是周围8个位的位置 ↑
//比如第一个方块类型0x51=(0101 0001)b那么这个方块就是↑
unsigned char AllBlocks[26]={
0x51,0x54,0x15,0x45
,0x58,0x16,0x85,0x61
,0x43,0xd0,0x34,0x0d
,0x1c,0x07,0xc1,0x70
,0x4c,0x13,0xc4,0x31
,0x19,0x46,0x91,0x64
,0x44,0x11};
BlockInfo oldblock,currblock;
int score;
int speed;
int gameover;
unsigned short Panel[LINENUM];
int main()
{
int i;
char direction;
currblock.point.x=5;
currblock.point.y=5;
currblock.flags=0x15;
Panel[0]=0xffff;
Panel[LINENUM-1]=0xffff;
//界面和左右边界
for(i=1;i
speed=1;
//直到获取一个非0速度
do
{
printf("Please input the
value of speed:\n");
scanf("%d",&speed);
}while(speed == 0);
score=0;
gameover=0;
srand(time(0));
CreateBlock();
while(direction!='q' &&
gameover==0) //没有按下q键,且游戏者未挂掉
{
if(direction == KEY_DOWN)
{
_sleep(1000);
BlockDrop();
}
//游戏者未挂,且没有按键则自动下落
while(gameover==0 &&
!kbhit())
{
_sleep(600/speed);
//delay(60000/speed);
BlockDrop();
}
direction=getch(); //获取移动方向
if(direction == KEY_UP)ChangeType();//如果是上键,则变换方块类型
else if(direction != KEY_DOWN)
MoveBlock(direction);//如果不是上,不是下,则按方向移动方块
}
return 0;
}
void BlockDrop()
{
//原先方块的信息保存到oldblock中,后边相同的我就不注释了
oldblock.flags=currblock.flags;
oldblock.point.x=currblock.point.x;
oldblock.point.y=currblock.point.y;
//当前方块下落一格
currblock.point.y+=1;
//清除原先方块
ClearBlock(Panel,&oldblock);
if(!BlockCat(Panel,&currblock))//如果currblock是非法的,则
{
BlockCat(Panel,&oldblock);//把原先的方块放回界面上去
//不能下落了,则说明一个非常严重的问题--这个方块到底儿了
//1、判断是否有满行,并且进行处理
isFull();
//2、创建一个新的方块
CreateBlock();
}
//方块的现状显示出来
ShowInfo();
}
void ChangeType()
{
unsigned char now;
oldblock.flags=currblock.flags;
oldblock.point.x=currblock.point.x;
oldblock.point.y=currblock.point.y;
//now是原先的类型
now=currblock.flags;
now >>= 6;
//右移6位,now中剩下的是最左边2位
currblock.flags<<=2;//左移2位剩下的是右边的6位
currblock.flags|=now;//两者逻辑或,这样实现的操作如下图所示
// 1 2 3 7 8 1
// 8 + 4 ==>6 + 2
// 7 6 5 5 4 3
//也就是从12345678 变成了34567812,即方块向右旋转一次
ClearBlock(Panel,&oldblock);//清除原先方块
if(!BlockCat(Panel,&currblock))//如果可以currblock不合法,则
{
//将原先方块放回去
BlockCat(Panel,&oldblock);
//currblock永远保存的是当前方块
currblock.flags=oldblock.flags;
currblock.point.x=oldblock.point.x;
currblock.point.y=oldblock.point.y;
return; //没有变化,不用再次显示
}
ShowInfo();
}
void MoveBlock(int direction)
{
if(direction==KEY_LEFT)
{
oldblock.flags=currblock.flags;
oldblock.point.x=currblock.point.x;
oldblock.point.y=currblock.point.y;
currblock.point.x-=1; //向左移动一步
ClearBlock(Panel,&oldblock);
if(!BlockCat(Panel,&currblock))
{
BlockCat(Panel,&oldblock);
currblock.point.x++;
}
ShowInfo();
}
else if(direction==KEY_RIGHT)
{
oldblock.flags=currblock.flags;
oldblock.point.x=currblock.point.x;
oldblock.point.y=currblock.point.y;
currblock.point.x+=1;
ClearBlock(Panel,&oldblock);
if(!BlockCat(Panel,&currblock))
{
BlockCat(Panel,&oldblock);
currblock.point.x--;
}
ShowInfo();
}
}
int BlockCat(unsigned short Panel[], BlockInfo
*currblock)
{
int row=currblock->point.y;
int col=currblock->point.x;
if((currblock->flags & 1)
&& (Panel[row-1]
& 1<<15-col))
return false;
if((currblock->flags &
1<<1)
&& (Panel[row-1]
& 1<<15-col-1))
return false;
if((currblock->flags &
1<<2)
&& (Panel[row]
& 1<<15-col-1))
return false;
if((currblock->flags &
1<<3)
&& (Panel[row+1]
& 1<<15-col-1))
return false;
if((currblock->flags &
1<<4)
&& (Panel[row+1]
& 1<<15-col))
return false;
if((currblock->flags &
1<<5)
&& (Panel[row+1]
& 1<<15-col+1))
return false;
if((currblock->flags &
1<<6)
&& (Panel[row]
& 1<<15-col+1))
return false;
if((currblock->flags &
1<<7)
&& (Panel[row-1]
& 1<<15-col+1))
return false;
if(Panel[row] &
1<<15-col)return false;
if(currblock->flags & (1)
) Panel[row-1] |=
(1<<15-col) ;
if(currblock->flags &
(1<<1) ) Panel[row-1] |=
(1<<15-col-1) ;
if(currblock->flags &
(1<<2) ) Panel[row]
|= (1<<15-col-1)
;
if(currblock->flags &
(1<<3) ) Panel[row+1] |=
(1<<15-col-1) ;
if(currblock->flags &
(1<<4) ) Panel[row+1] |=
(1<<15-col) ;
if(currblock->flags &
(1<<5) ) Panel[row+1] |=
(1<<15-col+1) ;
if(currblock->flags &
(1<<6) ) Panel[row]
|= (1<<15-col+1)
;
if(currblock->flags &
(1<<7) ) Panel[row-1] |=
(1<<15-col+1) ;
Panel[row] |=(1<<15-col);
return true;
}
void ClearBlock(unsigned short Panel[], BlockInfo
*block)
{
int row=block->point.y;
int col=block->point.x;
Panel[row] &=
~(1<<15-col);
if(block->flags & (1)
){Panel[row-1]
&= ~(1<<15-col)
;}
if(block->flags &
(1<<1) ){Panel[row-1]
&= ~(1<<15-col-1)
;}
if(block->flags &
(1<<2) ){Panel[row]
&=
~(1<<15-col-1) ;}
if(block->flags &
(1<<3) ){Panel[row+1]
&= ~(1<<15-col-1)
;}
if(block->flags &
(1<<4) ){Panel[row+1]
&= ~(1<<15-col)
;}
if(block->flags &
(1<<5) ){Panel[row+1]
&= ~(1<<15-col+1)
;}
if(block->flags &
(1<<6) ){Panel[row]
&=
~(1<<15-col+1) ;}
if(block->flags &
(1<<7) ){Panel[row-1]
&= ~(1<<15-col+1)
;}
}
void CreateBlock()
{
int i,j;
//方块初始位置固定为5,2,也就是第6行,第3列
currblock.point.x=5;
currblock.point.y=2;
//currblock.flags=0;
//随机产生一个类型的方块
currblock.flags=AllBlocks[rand()&];
//如果放不下这个方块,则说明游戏结束了
if(!BlockCat(Panel,&currblock))
{
gameover=1;
GameOver();
}
}
void ShowInfo()
{
char *panel;
int i,j;
char str[32];
unsigned int temp;
// gotoxy(1,1);
// clrscr();
system("cls");//清屏
//显示得分
printf("\n");
printf("SCORE: [ %d
]\n",score);
//循环输出每一行
for(i=0;i
{
j=30;//共有16个位和15个空格,所以是0~30,第31个字符是'\0'
temp=Panel[i];
while(temp)
{
if(temp%2==0)str[j--]=' '; //这个位是0则输出空格
else str[j--]='1'; //是1则输出1
str[j--] = ' '; //前边都加个空格是为了界面好看
temp/=2;
}
str[31]='\0';
printf(str); //输出本行
printf("\n");
}
}
void isFull()
{
int i,j;
for(i=LINENUM-2;i>0;i--)
{
if((unsigned short)~Panel[i]==3)//满了的行会是这样的(1 111111111111 1
00),非运算后是3
{ // ↑ ↑
↑
Panel[i]=0x8004; // 左边界 方块 右边界
score+=10;
for(j=i;j>1;j--)Panel[j]=Panel[j-1];//满的行消除,其余行依次下落
Panel[1]=0x8004;
}
}
}
void GameOver()
{
printf("Game Over");
}