C++实现的俄罗斯方块(参考)
- 格式:pdf
- 大小:155.98 KB
- 文档页数:17
C语⾔实现俄罗斯⽅块(转)原⽂地址如下:在图书馆看到⼀本书有俄罗斯⽅块的源程序⾃⼰当年也是俄罗斯⽅块的爱好者便想分析分析这个⼩游戏的源代码这⼏天有空就看了看发现读源码对编程领悟很有帮助读完深深的感觉到程序的确是好的数据结构加上好的算法这段程序定义了两个数据结构分别是//游戏底板结构,表⽰每个⼩⽅块所具有的属性struct BOARD{//当前状态,只有0或1,1表⽰次⼩⽅块已被占⽤int var;//⼩⽅块的颜⾊int color;}Table_board[Vertical_boxs][Horizontal_boxs];//游戏跳出的⽅块结构struct SHAPE{//⼀个字节等于8位,每四位来表⽰⼀个游戏⽅块的⼀⾏//如box[0]="0x88",box[1]="oxc0"表⽰的是://1000//1000//1100//0000//以此来表⽰游戏⽅块的各种形状char box[2];//游戏⽅块的颜⾊int color;//下⼀个游戏⽅块的编号int next;//这个next设计的也是相当妙啊};该源码的算法更确切的说是游戏的逻辑读完也是很有体会把握好⼤的系统强⼤的逻辑能⼒是必要的平时⾃⼰还是要再数据结构和算法这些⽅⾯加强学习、锻炼这段程序还有就是中断不是很理解还需要时间领悟⼀下下⾯贴⼀下我的程序注释这个游戏的层次描述:1预览功能2控制功能俄罗斯⽅块 3显⽰更新功能4分数更新功能5游戏帮助功能下⾯是源码:(该程序⽤到了TC的图形库,所以VC下是运⾏不了的,不过VC做代码编辑阅读⽐较⽅便,所以代码注释采⽤了VC下的//)//加载头⽂件#include <stdio.h>#include <stdlib.h>#include <dos.h>#include <graphics.h>//加载tc图形库//定义按键码#define VK_LEFT 0x4b00#define VK_RIGHT 0x4d00#define VK_DOWN 0x5000#define VK_UP 0x4800#define VK_ESC 0x011b//设置中断号 1c:时钟中断时得到控制权,若要固定时间发⽣事件,可以通过修改1c中断来得到#define TIMER 0x1c//共有19种形态的游戏⽅块#define MAX_BOX 19//⽅块的边长为20#define BSIZE 20//显⽰游戏界⾯的左上⾓x坐标#define Sys_x 160//显⽰游戏界⾯的左上⾓y坐标#define Sys_y 25//⽔平⽅向的⽅块数量#define Horizontal_boxs 10//垂直⽅向的⽅块数量#define Vertical_boxs 15//第⼀个游戏⽅块的产⽣起始位置#define Begin_boxs_x Horizontal_boxs/2//前景⾊#define FgColor 3//背景⾊#define BgColor 0//右边状态栏的x坐标#define LeftWin_x Sys_x+Horizontal_boxs*BSIZE+46#define false 0#define true 1//移动的⽅向#define MoveLeft 1#define MoveRight 2#define MoveDown 3#define MoveRoll 4//保存当前游戏⽅块编号int current_box_numb;//保存游戏⽅块的当前坐标int Curbox_x=Sys_x+Begin_boxs_x*BSIZE,Curbox_y=Sys_y;//是否要产⽣新游戏⽅块int flag_newbox=false;//下落速度int speed=1;//游戏得分int score=0;//每等级所需要分数int speed_step=30;//指向原来时钟中断处理过程⼊⼝的中断处理函数指针关键字interrupt指定⼀个函数应该被看成⼀个中断函数void interrupt(*oldtimer)(void);//游戏底板结构,表⽰每个⼩⽅块所具有的属性struct BOARD{//当前状态,只有0或1,1表⽰次⼩⽅块已被占⽤int var;//⼩⽅块的颜⾊int color;}Table_board[Vertical_boxs][Horizontal_boxs];//游戏跳出的⽅块结构struct SHAPE{//⼀个字节等于8位,每四位来表⽰⼀个游戏⽅块的⼀⾏//如box[0]="0x88",box[1]="oxc0"表⽰的是://1000//1000//1100//0000//以此来表⽰游戏⽅块的各种形状char box[2];//游戏⽅块的颜⾊int color;//下⼀个游戏⽅块的编号int next;};//初始化游戏⽅块的内容,包括形状颜⾊和下⼀个游戏⽅块编号struct SHAPE shapes[MAX_BOX]={{0x88,0xc0,CYAN,1},{0xe8,0x0,CYAN,2},{0xc4,0x40,CYAN,3},{0x2e,0x0,CYAN,0},{0x44,0xc0,MAGENTA,5},{0x8e,0x0,MAGENTA,6},{0xc8,0x80,MAGENTA,7},{0xe2,0x0,MAGENTA,4},{0x8c,0x40,YELLOW,9},{0x6c,0x0,YELLOW,8},{0x4c,0x80,BROWN,11},{0xc6,0x0,BROWN,10},{0x4e,0x0,WHITE,13},{0x8c,0x80,WHITE,14},{0xe4,0x0,WHITE,15},{0x4c,0x40,WHITE,12},{0x88,0x88,RED,17},{0xf0,0x0,RED,16},{0xcc,0x0,BLUE,18},};//定时计数器变量unsigned int TimerCounter=0;//以下为函数声明void initialize(int,int,int,int);void interrupt newtimer(void);void SetTimer(void interrupt(*IntProc)(void));void KillTimer(void);void ShowScore(int);void ShowSpeed(int);void show_help(int,int);void setFullRow(int);int DelFullRow(int);void show_box(int,int,int,int);void EraseBox(int,int,int);void ErasePreBox(int,int,int);int MkNextBox(int);int MoveAble(int,int,int,int);//主函数void main(){int GameOver=0;int key,nextbox;int Currentaction=0;int gd=VGA,gm=VGAHI,errorcode;initgraph(&gd,&gm,"");errorcode=graphresult();if(errorcode!=grOk){printf("\nNotice:Graphics error: %s\n",grapherrormsg(errorcode));printf("Press any key to quit!");getch();exit(1);}setbkcolor(BgColor);setcolor(FgColor);randomize();SetTimer(newtimer);initialize(Sys_x,Sys_y,Horizontal_boxs,Vertical_boxs);//初始化nextbox=MkNextBox(-1);show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); show_box(LeftWin_x,Curbox_y+320,nextbox,shapes[nextbox].color);show_help(Sys_x,Curbox_y+320);getch();while (1){Currentaction=0;flag_newbox=false;//int bioskey(int cmd)//完成直接键盘操作,cmd的值决定执⾏什么操作//cmd=0,返回下⼀个键盘键⼊的值//cmd=1,查询是否按下⼀个键,若按下⼀个键返回⾮零值,否则返回0if(bioskey(1)){key=bioskey(0);}else{key=0;}switch(key){case VK_LEFT:if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveLeft)){EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x-=BSIZE;Currentaction=MoveLeft;}break;case VK_RIGHT:if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveRight)){EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_x+=BSIZE;Currentaction=MoveRight;}break;case VK_DOWN:if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)){EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE;Currentaction=MoveDown;}elseflag_newbox=true;break;case VK_UP:if(MoveAble(Curbox_x,Curbox_y,shapes[current_box_numb].next,MoveRoll)){EraseBox(Curbox_x,Curbox_y,current_box_numb);current_box_numb=shapes[current_box_numb].next;Currentaction=MoveLeft;}break;case VK_ESC:GameOver=1;break;default:break;}if (Currentaction)//当前有动作就执⾏{show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); Currentaction=0;}if(flag_newbox)//按了向下键,但不能下移就产⽣新的游戏⽅块{ErasePreBox(LeftWin_x,Sys_y+200,nextbox);nextbox=MkNextBox(nextbox);show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color);if(!MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)){show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); GameOver=1;}else{flag_newbox=false;}Currentaction=0;}else//⾃由下落{if(Currentaction==MoveDown||TimerCounter>(20-speed*2)){if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown)){EraseBox(Curbox_x,Curbox_y,current_box_numb);Curbox_y+=BSIZE;show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color); }TimerCounter=0;}}if(GameOver){printf("game over,thank you! your score is %d",score);getch();break;}}getch();KillTimer();closegraph();}//******************************************************************** //显⽰帮助,提⽰⽤户如何进⾏游戏的相关操作//void show_help(int xs,int ys){char stemp[50];setcolor(15);//void far rectangle(int x0,int y0,int x1,int y1)//以(x0,y0)为左上⾓,(x1,x2)为右下⾓画⼀个矩形框rectangle(xs,ys,xs+239,ys+100);//sprintf()//将字串格式化到字符串sprintf(stemp," -Roll -Downwards");stemp[0]=24;stemp[8]=25;setcolor(14);//void far outtextxy(int x,int y,char far *text)//将⽂本输出到指定位置outtextxy(xs+40,ys+30,stemp);sprintf(stemp," -Turn Left -Turn Right");stemp[0]=27;stemp[13]=26;outtextxy(xs+40,ys+45,stemp);outtextxy(xs+40,ys+60,"Esc-Exit");setcolor(FgColor);}//******************************************************************* //对游戏界⾯的初始化void initialize(int x,int y,int m,int n){int i,j,oldx;oldx=x;for(j=0;j<n;j++){for(i=0;i<m;i++){Table_board[j][i].var=0;Table_board[j][i].color=BgColor;line(x,y,x+BSIZE,y);line(x,y,x,y+BSIZE);line(x,y+BSIZE,x+BSIZE,y+BSIZE);line(x+BSIZE,y,x+BSIZE,y+BSIZE);x+=BSIZE;}y+=BSIZE;x=oldx;}Curbox_x=x;Curbox_y=y;flag_newbox=false;speed=1;score=0;ShowScore(score);ShowSpeed(speed);}//*************************************************************//显⽰当前⽤户的成绩void ShowScore(int score){int x,y;char score_str[5];setfillstyle(SOLID_FILL,BgColor);y=100;//确定⼀个以(x0,y0)为左上⾓,(x1,x2)为右下⾓的矩形窗⼝,再按规定图形和颜⾊填充bar(x-BSIZE,y,x+BSIZE*3,y+BSIZE*3);sprintf(score_str,"%3d",score);outtextxy(x,y,"SCORE");outtextxy(x,y+10,score_str);}//**********************************************************//显⽰当前下落速度void ShowSpeed(int speed){int x,y;char speed_str[5];setfillstyle(SOLID_FILL,BgColor);x=LeftWin_x;y=150;bar(x-BSIZE,y,x+BSIZE*3,y+BSIZE*3);sprintf(speed_str,"%3d",speed);outtextxy(x,y,"Level");outtextxy(x,y+10,speed_str);outtextxy(x,y+50,"Nextbox");}//**********************************************************//定义新的时钟中断处理函数void interrupt newtimer(void){//调⽤原来的例程(*oldtimer)();//全局计数器变量加1TimerCounter++;}//********************************************************//设置新的时钟中断处理void SetTimer(void interrupt (*IntProc)(void)){//获取中断号为TIMER的中断处理函数的⼊⼝地址oldtimer=getvect(TIMER);//设置新的时钟中断处理过程时,禁⽌所有中断disable();//将中断号为TIMER的中断处理函数⼊⼝地址改为IntProc()函数的⼊⼝地址setvect(TIMER,IntProc);//开启中断enable();}//*********************************************************//恢复原有的时钟中断处理过程void KillTimer(){disable();setvect(TIMER,oldtimer);enable();}//********************************************************//在(x,y)位置开始,⽤指定的颜⾊显⽰编号为box_num的游戏⽅块void show_box(int x,int y,int box_num,int color){int i,ii,ls_x=x;//指定的游戏⽅块不存在if(box_num<0||box_num>=MAX_BOX)box_num=MAX_BOX/2;//void far setfillstyle(int pattern,int color)//以pattern为填充模式以color为填充颜⾊对指定图形进⾏填充setfillstyle(SOLID_FILL,color);{int mask=128;//掩码,⽤于位运算//单个⽅块填充for(i=0;i<8;i++){if(i%4==0&&i!=0)//表⽰转到游戏⽅块的下⼀⾏了{y+=BSIZE;x=ls_x;}if((shapes[box_num].box[ii])&mask){bar(x,y,x+BSIZE,y+BSIZE);line(x,y,x+BSIZE,y);line(x,y,x,y+BSIZE);line(x,y+BSIZE,x+BSIZE,y+BSIZE);line(x+BSIZE,y,x+BSIZE,y+BSIZE);}x+=BSIZE;mask/=2;}y+=BSIZE;x=ls_x;}}//***************************************************************//清除(x,y)位置开始的编号为box_num的boxvoid EraseBox(int x,int y,int box_num){int mask=128,t_boardx,t_boardy,n,m;setfillstyle(SOLID_FILL,BgColor);for(n=0;n<4;n++){for (m=0;m<4;m++){if(((shapes[box_num].box[n/2])&mask)){bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE);line(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE,y+n*BSIZE+BSIZE);line(x+m*BSIZE,y+n*BSIZE+BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE); line(x+m*BSIZE+BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE); }mask/=2;if(mask==0)mask=128;}}}//*******************************************************//同EraseBox()void ErasePreBox(int x,int y,int box_numb){int mask=128,t_boardx,t_boardy,n,m;setfillstyle(SOLID_FILL,BgColor);for(n=0;n<4;n++){for(m=0;m<4;m++){if(((shapes[box_numb].box[n/2])&mask)){bar(x+m*BSIZE,y+n*BSIZE,x+m*BSIZE+BSIZE,y+n*BSIZE+BSIZE);}mask/=2;if(mask==0)mask=128;}}}//***************************************************************//将新图形的游戏⽅块放置在游戏板上,并返回此游戏⽅块号int MkNextBox(int box_numb){int mask=128,t_boardx,t_boardy,n,m;t_boardx=(Curbox_x-Sys_x)/BSIZE;t_boardy=(Curbox_y-Sys_y)/BSIZE;for(n=0;n<4;n++){for(m=0;m<4;m++){if(((shapes[current_box_numb].box[n/2])&mask)){//设置游戏⽅块Table_board[t_boardy+n][t_boardx+m].var=1;Table_board[t_boardy+n][t_boardx+m].color=shapes[current_box_numb].color;}mask=mask/2;if(mask==0)mask=128;}}setFullRow(t_boardy);//初始化坐标Curbox_x=Sys_x+Begin_boxs_x*BSIZE;Curbox_y=Sys_y;if(box_numb==-1)box_numb=rand()%MAX_BOX;//随机产⽣游戏⽅块current_box_numb=box_numb;flag_newbox=false;return (rand()%MAX_BOX);}//***********************************************************//⽤于找到满⾏,参数t_boardy表⽰当前的游戏⽅块号void setFullRow(int t_boardy){int n,full_numb=0,top=0;//top保存当前游戏主板在消除满⾏后的最⾼点,⽤于游戏主板的重绘register m;//寄存器类型,存取速度快for(n=t_boardy+3;n>=t_boardy;n--){if(n<0||n>=Vertical_boxs)continue;for(m=0;m<Horizontal_boxs;m++){if(!Table_board[n+full_numb][m].var)//发现有⼀个是空的就跳过break;}if(m==Horizontal_boxs)//找到满⾏{if(n==t_boardy+3)top=DelFullRow(n+full_numb);//清除该⾏,并保存最⾼点elseDelFullRow(n+full_numb);full_numb++;//保存满⾏的⾏数}}if(full_numb)//存在满⾏{int oldx,x=Sys_x,y=BSIZE*top+Sys_y;oldx=x;score=score+full_numb*10;for(n=top;n<t_boardy+4;n++){if(n>=Vertical_boxs)continue;//重绘游戏主板for(m=0;m<Horizontal_boxs;m++){if(Table_board[n][m].var){setfillstyle(SOLID_FILL,Table_board[n][m].color);}elsesetfillstyle(SOLID_FILL,BgColor);bar(x,y,x+BSIZE,y+BSIZE);line(x,y,x+BSIZE,y);line(x,y,x,y+BSIZE);line(x,y+BSIZE,x+BSIZE,y+BSIZE);line(x+BSIZE,y,x+BSIZE,y+BSIZE);x+=BSIZE;}y+=BSIZE;x=oldx;}ShowScore(score);if(speed!=score/speed_step){speed=score/speed_step;ShowSpeed(speed);}elseShowSpeed(speed);}}//************************************************************//处理删除⾏,参数y指明具体哪⼀⾏为满⾏int DelFullRow(int y){int n,top=0;register m,totoal;for (n=y;n>=0;n--){totoal=0;for(m=0;m<Horizontal_boxs;m++){if(!Table_board[n][m].var)totoal++;//没有⽅格,对计数器加1//上⾏不等于下⾏就把上⾏传给下⾏,此处为程序优化部分,也可不优化 if(Table_board[n][m].var!=Table_board[n-1][m].var){Table_board[n][m].var=Table_board[n-1][m].var;Table_board[n][m].color=Table_board[n-1][m].color;}}//发现上⾯有连续的空⾏,提前结束if (totoal==Horizontal_boxs){top=n;break;}}return top;//返回最⾼点}//********************************************************8//判断⽅块是否可以移动,(x,y)为当前游戏⽅块位置,box_numb为游戏⽅块号,direction为动作标识int MoveAble(int x,int y,int box_numb,int direction){int n,m,t_boardx,t_boardy;int mask;if(direction==MoveLeft)//如果向左移动{mask=128;x-=BSIZE;t_boardx=(x-Sys_x)/BSIZE;t_boardy=(y-Sys_y)/BSIZE;for(n=0;n<4;n++){for(m=0;m<4;m++){if((shapes[box_numb].box[n/2])&mask){if((x+BSIZE*m)<Sys_x)//碰到最左边return false;else if(Table_board[t_boardy+n][t_boardx+m].var)//左移⼀个单位后,与游戏主板冲突return false;}mask/=2;if(mask==0)mask=128;}}return true;}else if(direction==MoveRight)//右移动{x+=BSIZE;t_boardx=(x-Sys_x)/BSIZE;t_boardy=(y-Sys_y)/BSIZE;mask=128;for(n=0;n<4;n++){for(m=0;m<4;m++){if((shapes[box_numb].box[n/2])&mask){if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs))//碰到最右边return false;else if(Table_board[t_boardy+n][t_boardx+m].var)//与游戏主板冲突return false;}mask/=2;if(mask==0)mask=128;}}return true;}else if(direction==MoveDown)//下移动{mask=128;y+=BSIZE;t_boardx=(x-Sys_x)/BSIZE;t_boardy=(y-Sys_y)/BSIZE;for(n=0;n<4;n++){for(m=0;m<4;m++){if((shapes[box_numb].box[n/2])&mask){if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs)||Table_board[t_boardy+n][t_boardx+m].var)//碰到最下边或向下有冲突 {flag_newbox=true;break;}}mask/=2;if(mask==0)mask=128;}}if(flag_newbox)return false;elsereturn true;}else if(direction==MoveRoll)//旋转{mask=128;t_boardx=(x-Sys_x)/BSIZE;t_boardy=(y-Sys_y)/BSIZE;for(n=0;n<4;n++){for(m=0;m<4;m++){if((shapes[box_numb].box[n/2])&mask){if((y+BSIZE*n)>=(Sys_y+BSIZE*Vertical_boxs))//碰到最下边return false;if((x+BSIZE*n)>=(Sys_x+BSIZE*Horizontal_boxs))//碰到最左边return false;if((x+BSIZE*m)>=(Sys_x+BSIZE*Horizontal_boxs))//碰到最右边return false;else if (Table_board[t_boardy+n][t_boardx+m].var)//向下有冲突{return false;}}mask/=2;if(mask==0)mask=128;}}return true;}elsereturn false;}。
C语言编写俄罗斯方块实验报告实验报告一、实验目的实践C语言的基本语法和操作,测试自己对C语言的熟练程度,实现俄罗斯方块游戏的基本功能。
二、实验步骤1.定义游戏界面:使用二维数组定义游戏界面,用字符来表示方块的状态(空白、正在下落的方块、已经固定的方块)。
2.实现方块的生成和选择:定义方块的类型,通过随机数生成下一个方块,用一个变量来保存下一个方块的类型,并在游戏界面上进行展示。
3.实现方块的下落和移动:方块可以通过用户的操作左右移动和旋转,同时也会自动下落,每当方块到达底部或者碰到已经固定的方块时,就会停止下落。
4.实现方块的旋转:将方块表示为二维数组,通过改变数组元素的位置实现方块的旋转。
5.实现方块的消除:当一行方块被填满时,该行会消除,并且上面的方块会下落填充空缺。
三、实验结果成功实现了俄罗斯方块的基本功能,可以进行游戏的开始、暂停、重新开始、结束等操作。
在游戏过程中,方块可以通过键盘的方向键左右移动,通过按下空格键进行快速下落,通过旋转方向键进行方块的旋转。
当方块都不能下落时,游戏结束,会提示游戏结束的信息,并显示最终得分。
四、实验总结通过本次实验,我进一步了解了C语言的基本语法和操作,也体验到了编程的乐趣。
通过这个实验,我对C语言有了更深入的理解,在实现俄罗斯方块的过程中锻炼了自己的逻辑思维能力和编程能力。
同时,我也学会了如何进行代码的调试和优化,使得程序的运行更加流畅和高效。
在后续的学习中,我将更加深入地学习C语言的高级特性,不断提升自己的编程水平。
通过不断的实践和练习,我相信我可以在C语言编程方面取得更进一步的进展,完成更加复杂和有挑战性的任务。
总体而言,本次实验收获颇多,不仅提高了我的编程能力,也为我的学习之路打下了良好的基础。
我相信在今后的学习和工作中,这些经验将会成为我不断进步的动力和宝贵的财富。
俄罗斯方块变形c语言在C语言中实现俄罗斯方块游戏是一项复杂的任务,涉及到图形界面、游戏逻辑和事件处理等多个方面。
以下是一个简化版的俄罗斯方块游戏示例,使用字符在控制台中显示游戏界面。
c复制代码#include<stdio.h>#include<stdlib.h>#include<unistd.h>#define WIDTH 20#define HEIGHT 10typedef enum {BLOCK_EMPTY,BLOCK_I,BLOCK_J,BLOCK_L,BLOCK_O,BLOCK_S,BLOCK_Z} BlockType;typedef struct {BlockType type;int x;int y;} Block;Block board[WIDTH][HEIGHT];BlockType currentBlock = BLOCK_I;int rotation = 0;int x = WIDTH / 2;int y = HEIGHT - 1;void drawBoard() {for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { char ch = ' ';switch (board[i][j].type) {case BLOCK_EMPTY:ch = '.';break;case BLOCK_I:ch = 'I';break;case BLOCK_J:ch = 'J';break;case BLOCK_L:ch = 'L';break;case BLOCK_O:ch = 'O';break;case BLOCK_S:ch = 'S';break;case BLOCK_Z:ch = 'Z';break;}printf("%c", ch);}printf("\n");}}void updateBoard() {for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++) {if (board[i][j].type != BLOCK_EMPTY) {board[i][j].y--; // Move block down one row.} else { // Place new block.switch (currentBlock) { // Place based on current block type.case BLOCK_I: // Place full I-block.board[i][j].type = BLOCK_I; // Column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column j Y n Row Y j Columns n - j 1 -- i 1 i - i j Row i Row i - 1 i Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i - - - - - - - - - - - - - - -。
//俄罗斯方块#include "stdio.h"#include "conio.h"#include "stdlib.h"#include "windows.h"#include "time.h"#define N 17#define M 13#define K 19int s[N][M]={{0,0,0},{0,0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, {1},{1,0,0,1},{1,1,1,1,1,1,0,1,1,0,0,1,1}};/*当前状态*/inta[K][3][3]={{0,2,0,2,2,2},{0,2,0,2,2,0,0,2},{0,2,0,0,2,2,0,2},{2,2,2,0,2},{2,2,2,0,0,2 ,0},{2,0,0,2,2,2},{2,0,0,2,0,0,2,2},{0,0,2,0,0,2,0,2,2},{0,0,2,2,2,2},{2,2,2,2,0,0}, {2,2,0,0,2,0,0,2,0},{0,2,2,0,2,0,0,2,0},{{2},{2},{2}},{2,2,2},{2,2,0,2,2,0},{2,0,0,2,2,0,0,2},{0,0,2,0,2,2,0,2},{2,2,0,0,2,2},{0,2,2,2,2,0}};void Disp(){int i,j;for(i=0;i<N;i++){for(j=0;j<M;j++)printf("%c",s[i][j]?48+s[i][j]:' ');printf("┃\n");}printf("━━━━━━━━");printf("\n\n操作说明:A-->左移,D-->右移,W-->变形,ESC-->退出\n");}void Down(){int i,j,k;for(j=0;j<M;j++)if(s[N-1][j]==2)break;/*判断是否在下边界*/if(j<M)/*若方块在下边界则将方块由2变1;因为用两种不同的符号,容易判断方块是否“着陆”及左右移动时,是否碰壁*/{for(i=0;i<N;i++)for(j=0;j<M;j++)if(s[i][j]==2)s[i][j]=1;for(i=N-1;i>=0;i--){for(j=0;j<M;j++)//判断第i行是否有空格if(s[i][j]==0)break;if(j==M)/*若第i行没空格消去第i行*/for(k=i++-1;k>=0;k--)//?for(j=0;j<M;j++)s[k+1][j]=s[k][j];}return;}for(i=0;i<N-1;i++){for(j=0;j<M;j++)if(s[i][j]==2)if(s[i+1][j]!=0&&s[i+1][j]!=2)break;/*方块下方不空说明触到1了退出内循环*/ if(j<M)break;/*方块下方不空退出外循环*/}if(i<N-1||j<M){for(i=0;i<N;i++)//若已触到1则将方块由 2变1*/for(j=0;j<M;j++)if(s[i][j]==2)s[i][j]=1;for(i=N-1;i>=0;i--){for(j=0;j<M;j++)if(s[i][j]==0)break;//判断第i行是否有空格if(j==M)/*若第i行没空格消去第i行*/for(k=i++-1;k>=0;k--)for(j=0;j<M;j++)s[k+1][j]=s[k][j];}return;}for(i=N-1;i>=0;i--)for(j=0;j<M;j++)if(s[i][j]==2)s[i+1][j]=s[i][j],s[i][j]=0;/*方块下移*/}void Right(){int i,j;for(i=0;i<N;i++)if(s[i][M-1]==2)return;/* 已经在右边界退出 */for(i=0;i<N;i++)for(j=0;j<M-1;j++)if(s[i][j]==2)if(s[i][j+1]!=0&&s[i][j+1]!=2)return;/* 方块右方不空,即方块右边有1 退出 */ for(j=M-2;j>=0;j--)for(i=0;i<N;i++)if(s[i][j]==2)s[i][j+1]=s[i][j],s[i][j]=0;/* 方块右移 */}void Left(){int i,j;for(i=0;i<N;i++)if(s[i][0]==2)return;/* 已经在左边界退出 */for(i=0;i<N;i++)for(j=1;j<M;j++)if(s[i][j]==2)if(s[i][j-1]!=0&&s[i][j-1]!=2)return;/* 方块左方不空退出 */ for(j=1;j<M;j++)for(i=0;i<N;i++)if(s[i][j]==2)s[i][j-1]=s[i][j],s[i][j]=0;/* 方块左移 */}int Have()/*判断是否有可移动方块,没有返回1,否则返回0*/{int i,j;for(i=0;i<N;i++)for(j=1;j<M;j++)if(s[i][j]==2)return 0;return 1;}int Add()/*随机生成方块*/{int t,x;/*生成两随机数t和x分别作为第t种方块和第x位置出现*/int i,j;srand((unsigned int)time(NULL));t=rand()%K;x=rand()%(M-3);if(x<0) x=-x%(M-3);//?for(i=0;i<3;i++)for(j=x;j<x+3;j++)//把生成的方块存到初状态中s[i][j]=a[t][i][j-x];}void bianxing(int t,int n){int i,j,k,m,x,y;for(i=0;i<N;i++)//首先扫描是否有移动方块;及方块变形前的位置“行、列”{m=-1;for(j=0;j<M;j++)if(s[i][j]==2){m=i,x=j,y=i;break;//y,x记录所在行、列;并退出内循环}if(m!=-1)//m!=-1证明有移动方块break;//退出外循环}if(m!=-1)//m!=-1证明有移动方块{if(x+3>M||y+3>N) return;//判断是否有可变形空间,没有就返回for(i=y;i<y+3;i++)//判断是否有3*3的变形空间,没有就返回for(j=x;j<x+3;j++)if(s[i][j]==1) return;/*擦除当前移动方块;因为上面判断3*3的移动空间,是从上面开始扫描,遇到第一个小格子时,依他为基点向右下方扫描是否有3*3的空间;显然只进行下面的变形--存储是不行的;如:002002022-->2220020时,显然前面的方格倒数第二个2,留在了3*3变形空间的外面,输出图形将多一个格子,所以要在变形-->存储操作前进行擦除操作*/for(i=y;i<y+3;i++)for(j=0;j<M;j++)if(s[i][j]==2)s[i][j]=0;//变形并把它存储到当前状态中if(t<=3&&t>=0){static int h1;if(h1>n)h1=0;for(i=y;i<y+3;i++)//把方块存储到当前状态中for(j=x;j<x+3;j++)s[i][j]=a[h1][i-y][j-x];h1++;}else if(t<=11&&t>=4){static int h2=4;if(h2>n)h2=4;for(i=y;i<y+3;i++)//把方块存储到当前状态中for(j=x;j<x+3;j++)s[i][j]=a[h2][i-y][j-x];h2++;}else if(t<=13&&t>=12){static int h3=12;if(h3>n)h3=12;for(i=y;i<y+3;i++)//把方块存储到当前状态中for(j=x;j<x+3;j++)s[i][j]=a[h3][i-y][j-x];h3++;}else if(t<=18&&t>=15){static int h4=15;if(h4>n)h4=0;for(i=y;i<y+3;i++)//把方块存储到当前状态中for(j=x;j<x+3;j++)s[i][j]=a[h4][i-y][j-x];h4++;}}void main(){char c;int i=0,t;char str[][50]={" ((`'-\"``\"\"-'`))"," ) - - ( "," / (o _ o) \ "," \ ( 0 ) /"," _'-.._'='_..-'_ "," /`;#'#'#.-.#'#'#;`\ "," \_)) '#' ((_/ "," #. ☆ Game ☆ # "," '#. Over! .#' "," / '#. .#' \ "," _\ \'#. .#'/ /_"," (((___) '#' (___) ",""};system("color 0a");while(1)/*判断是否有按键,没有循环输出i,否则停,conio.h*/{if(!kbhit())/*kbhit用来判断是否有按键输入,若有按键返回非零值,否则返回零;没有按键时c被赋予一个“非操作键值”,它将一直下移;有按键是调用getch函数,读取键值*/c='2';elsec=getch();if(c=='p')//停止键;按任意键可解除停止getch();system("CLS");/*清屏,TC用clrscr();,VC用system("CLS");*/if(Have())//Have()判断是否有可移动方块,没有返回1,否则返回0t=Add();switch(c){case 'a':Left();break; /*左移*/case 'd':Right();break; /*右移*/case 27: system("pause");return; /*按Esc(=27)另存后退出*/default:;}//变形if(c=='w')if(t>=0&&t<=3) bianxing(t,3);else if(t>=4&&t<=11) bianxing(t,11);else if(t==12||t==13) bianxing(t,13);else if(t>=15&&t<=18) bianxing(t,18);c='2';Down();//判断方块的停、走和消除//判断顶层是否有1 有:游戏结束for(i=0;i<M;i++)if(s[0][i]==1){system("CLS");i=0;while(1){if(strlen(str[i])==0)break;printf("%s\n",str[i++]);}system("pause");exit(0);}Disp();//刷屏Sleep(500);/*睡眠ms,windows.h*/}}***********************************************************。
#include <stdio.h>#include <dos.h>#include <conio.h>#include <graphics.h>#include <stdlib.h>#ifdef__cplusplus#define __CPPARGS ...#else#define __CPPARGS#endif#define MINBOXSIZE 15 /* 最小方块的尺寸*/#define BGCOLOR 7 /* 背景着色*/#define GX 200#define GY 10#define SJNUM 10000 /* 每当玩家打到一万分等级加一级*/ /* 按键码*/#define VK_LEFT 0x4b00#define VK_RIGHT 0x4d00#define VK_DOWN 0x5000#define VK_UP 0x4800#define VK_HOME 0x4700#define VK_END 0x4f00#define VK_SPACE 0x3920#define VK_ESC 0x011b#define VK_ENTER 0x1c0d/* 定义俄罗斯方块的方向(我定义他为4种)*/#define F_DONG 0#define F_NAN 1#define F_XI 2#define F_BEI 3#define NEXTCOL 20 /* 要出的下一个方块的纵坐标*/#define NEXTROW 12 /* 要出的下一个方块的横从标*/#define MAXROW 14 /* 游戏屏幕大小*/#define MAXCOL 20#define SCCOL 100 /*游戏屏幕大显示器上的相对位置*/#define SCROW 60int gril[22][16]; /* 游戏屏幕坐标*/int col=1,row=7; /* 当前方块的横纵坐标*/int boxfx=0,boxgs=0; /* 当前寺块的形壮和方向*/int nextboxfx=0,nextboxgs=0,maxcol=22;/*下一个方块的形壮和方向*/ int minboxcolor=6,nextminboxcolor=6;int num=0; /*游戏分*/int dj=0,gamedj[10]={18,16,14,12,10,8,6,4,2,1};/* 游戏等级*//* 以下我用了一个3维数组来纪录方块的最初形状和方向*/int boxstr[7][4][16]={{{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},{{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},{{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},{1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},{1,1,1,0,0,0,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},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0}},{{0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{0,1,0,0,1,1,1,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}}};/* 随机得到当前方块和下一个方块的形状和方向*/void boxrad(){minboxcolor=nextminboxcolor;boxgs=nextboxgs;boxfx=nextboxfx;nextminboxcolor=random(14)+1;if(nextminboxcolor==4||nextminboxcolor==7||nextminboxcolor==8) nextminboxcolor=9;nextboxfx=F_DONG;nextboxgs=random(7);}/*初始化图形模试*/void init(int gdrive,int gmode){int errorcode;initgraph(&gdrive,&gmode,"e:\\tc");errorcode=graphresult();if(errorcode!=grOk){printf("error of: %s",grapherrormsg(errorcode));exit(1);}}/* 在图形模式下的清屏*/void cls(){setfillstyle(SOLID_FILL,0);setcolor(0);bar(0,0,640,480);}/*在图形模式下的高级清屏*/void clscr(int a,int b,int c,int d,int color){setfillstyle(SOLID_FILL,color);setcolor(color);bar(a,b,c,d);}/*最小方块的绘制*/void minbox(int asc,int bsc,int color,int bdcolor){int a=0,b=0;a=SCCOL+asc;b=SCROW+bsc;clscr(a+1,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE,color);if(color!=BGCOLOR){setcolor(bdcolor);line(a+1,b+1,a-1+MINBOXSIZE,b+1);line(a+1,b+1,a+1,b-1+MINBOXSIZE);line(a-1+MINBOXSIZE,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE); line(a+1,b-1+MINBOXSIZE,a-1+MINBOXSIZE,b-1+MINBOXSIZE); }}/*游戏中出现的文字*/void txt(int a,int b,char *txt,int font,int color){setcolor(color);settextstyle(0,0,font);outtextxy(a,b,txt);}/*windows 绘制*/void win(int a,int b,int c,int d,int bgcolor,int bordercolor){clscr(a,b,c,d,bgcolor);setcolor(bordercolor);line(a,b,c,b);line(a,b,a,d);line(a,d,c,d);line(c,b,c,d);}/* 当前方块的绘制*/void funbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+row+a)*MINBOXSIZE,(i+col+b)*MINBOXSIZE,color,bdcolor); }/*下一个方块的绘制*/void nextfunbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[nextboxgs][nextboxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+a)*MINBOXSIZE,(i+b)*MINBOXSIZE,color,bdcolor);}/*时间中断定义*/#define TIMER 0x1cint TimerCounter=0;void interrupt ( *oldhandler)(__CPPARGS);void interrupt newhandler(__CPPARGS){TimerCounter++;oldhandler();}void SetTimer(void interrupt (*IntProc)(__CPPARGS)){oldhandler=getvect(TIMER);disable();setvect(TIMER,IntProc);enable();}/*由于游戏的规则,消掉都有最小方块的一行*/void delcol(int a){int i,j;for(i=a;i>1;i--)for(j=1;j<15;j++){minbox(j*MINBOXSIZE,i*MINBOXSIZE,BGCOLOR,BGCOLOR);gril[i][j]=gril[i-1][j];if(gril[i][j]==1)minbox(j*MINBOXSIZE,i*MINBOXSIZE,minboxcolor,0);}/*消掉所有都有最小方块的行*/ void delete(){int i,j,zero,delgx=0;char *nm="00000";for(i=1;i<21;i++){zero=0;for(j=1;j<15;j++)if(gril[j]==0)zero=1;if(zero==0){delcol(i);delgx++;}}num=num+delgx*delgx*10;dj=num/10000;sprintf(nm,"%d",num);clscr(456,173,500,200,4);txt(456,173,"Number:",1,15);txt(456,193,nm,1,15);}/*时间中断结束*/void KillTimer(){disable();setvect(TIMER,oldhandler); enable();}/* 测试当前方块是否可以向下落*/ int downok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i+1][row+j])k=0;return(k);/* 测试当前方块是否可以向左行*/int leftok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j-1])k=0;return(k);}/* 测试当前方块是否可以向右行*/int rightok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j+1])k=0;return(k);}/* 测试当前方块是否可以变形*/int upok(){int i,j,k=1,a[4][4];for(i=0;i<4;i++)for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx+1][i];for(i=3;i>=0;i--)for(j=3;j>=0;j--)if(a[j] && gril[col+i][row+j])k=0;return(k);}/*当前方块落下之后,给屏幕坐标作标记*/ void setgril(){int i,j,a[4][4];funbox(0,0,minboxcolor,0);for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j])gril[col+i][row+j]=1;col=1;row=7;}/*游戏结束*/void gameover(){int i,j;for(i=20;i>0;i--)for(j=1;j<15;j++)minbox(j*MINBOXSIZE,i*MINBOXSIZE,2,0);txt(103,203,"Game Over",3,10);}/*按键的设置*/void call_key(int keyx){switch(keyx){case VK_DOWN: { /*下方向键,横坐标加一。
#include <stdio.h>#include <dos.h>#include <conio.h>#include <graphics.h>#include <stdlib.h>#ifdef__cplusplus#define __CPPARGS ...#else#define __CPPARGS#endif#define MINBOXSIZE 15 /* 最小方块的尺寸*/#define BGCOLOR 7 /* 背景着色*/#define GX 200#define GY 10#define SJNUM 10000 /* 每当玩家打到一万分等级加一级*/ /* 按键码*/#define VK_LEFT 0x4b00#define VK_RIGHT 0x4d00#define VK_DOWN 0x5000#define VK_UP 0x4800#define VK_HOME 0x4700#define VK_END 0x4f00#define VK_SPACE 0x3920#define VK_ESC 0x011b#define VK_ENTER 0x1c0d/* 定义俄罗斯方块的方向(我定义他为4种)*/#define F_DONG 0#define F_NAN 1#define F_XI 2#define F_BEI 3#define NEXTCOL 20 /* 要出的下一个方块的纵坐标*/#define NEXTROW 12 /* 要出的下一个方块的横从标*/#define MAXROW 14 /* 游戏屏幕大小*/#define MAXCOL 20#define SCCOL 100 /*游戏屏幕大显示器上的相对位置*/#define SCROW 60int gril[22][16]; /* 游戏屏幕坐标*/int col=1,row=7; /* 当前方块的横纵坐标*/int boxfx=0,boxgs=0; /* 当前寺块的形壮和方向*/int nextboxfx=0,nextboxgs=0,maxcol=22;/*下一个方块的形壮和方向*/ int minboxcolor=6,nextminboxcolor=6;int num=0; /*游戏分*/int dj=0,gamedj[10]={18,16,14,12,10,8,6,4,2,1};/* 游戏等级*//* 以下我用了一个3维数组来纪录方块的最初形状和方向*/int boxstr[7][4][16]={{{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},{{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},{{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},{1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},{1,1,1,0,0,0,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},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0}},{{0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{0,1,0,0,1,1,1,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}}};/* 随机得到当前方块和下一个方块的形状和方向*/void boxrad(){minboxcolor=nextminboxcolor;boxgs=nextboxgs;boxfx=nextboxfx;nextminboxcolor=random(14)+1;if(nextminboxcolor==4||nextminboxcolor==7||nextminboxcolor==8) nextminboxcolor=9;nextboxfx=F_DONG;nextboxgs=random(7);}/*初始化图形模试*/void init(int gdrive,int gmode){int errorcode;initgraph(&gdrive,&gmode,"e:\\tc");errorcode=graphresult();if(errorcode!=grOk){printf("error of: %s",grapherrormsg(errorcode));exit(1);}}/* 在图形模式下的清屏*/void cls(){setfillstyle(SOLID_FILL,0);setcolor(0);bar(0,0,640,480);}/*在图形模式下的高级清屏*/void clscr(int a,int b,int c,int d,int color){setfillstyle(SOLID_FILL,color);setcolor(color);bar(a,b,c,d);}/*最小方块的绘制*/void minbox(int asc,int bsc,int color,int bdcolor){int a=0,b=0;a=SCCOL+asc;b=SCROW+bsc;clscr(a+1,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE,color);if(color!=BGCOLOR){setcolor(bdcolor);line(a+1,b+1,a-1+MINBOXSIZE,b+1);line(a+1,b+1,a+1,b-1+MINBOXSIZE);line(a-1+MINBOXSIZE,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE); line(a+1,b-1+MINBOXSIZE,a-1+MINBOXSIZE,b-1+MINBOXSIZE); }}/*游戏中出现的文字*/void txt(int a,int b,char *txt,int font,int color){setcolor(color);settextstyle(0,0,font);outtextxy(a,b,txt);}/*windows 绘制*/void win(int a,int b,int c,int d,int bgcolor,int bordercolor){clscr(a,b,c,d,bgcolor);setcolor(bordercolor);line(a,b,c,b);line(a,b,a,d);line(a,d,c,d);line(c,b,c,d);}/* 当前方块的绘制*/void funbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+row+a)*MINBOXSIZE,(i+col+b)*MINBOXSIZE,color,bdcolor); }/*下一个方块的绘制*/void nextfunbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[nextboxgs][nextboxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+a)*MINBOXSIZE,(i+b)*MINBOXSIZE,color,bdcolor);}/*时间中断定义*/#define TIMER 0x1cint TimerCounter=0;void interrupt ( *oldhandler)(__CPPARGS);void interrupt newhandler(__CPPARGS){TimerCounter++;oldhandler();}void SetTimer(void interrupt (*IntProc)(__CPPARGS)){oldhandler=getvect(TIMER);disable();setvect(TIMER,IntProc);enable();}/*由于游戏的规则,消掉都有最小方块的一行*/void delcol(int a){int i,j;for(i=a;i>1;i--)for(j=1;j<15;j++){minbox(j*MINBOXSIZE,i*MINBOXSIZE,BGCOLOR,BGCOLOR); gril[i][j]=gril[i-1][j];if(gril[i][j]==1)minbox(j*MINBOXSIZE,i*MINBOXSIZE,minboxcolor,0);}}/*消掉所有都有最小方块的行*/void delete(){int i,j,zero,delgx=0;char *nm="00000";for(i=1;i<21;i++){zero=0;for(j=1;j<15;j++)if(gril[j]==0)zero=1;if(zero==0){delcol(i);delgx++;}}num=num+delgx*delgx*10;dj=num/10000;sprintf(nm,"%d",num);clscr(456,173,500,200,4);txt(456,173,"Number:",1,15);txt(456,193,nm,1,15);}/*时间中断结束*/void KillTimer(){disable();setvect(TIMER,oldhandler);enable();}/* 测试当前方块是否可以向下落*/int downok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i+1][row+j])k=0;return(k);}/* 测试当前方块是否可以向左行*/ int leftok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j-1])k=0;return(k);}/* 测试当前方块是否可以向右行*/ int rightok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j+1])k=0;return(k);}/* 测试当前方块是否可以变形*/int upok(){int i,j,k=1,a[4][4];for(i=0;i<4;i++)for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx+1][i]; for(i=3;i>=0;i--)for(j=3;j>=0;j--)if(a[j] && gril[col+i][row+j])k=0;return(k);}/*当前方块落下之后,给屏幕坐标作标记*/void setgril(){int i,j,a[4][4];funbox(0,0,minboxcolor,0);for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j])gril[col+i][row+j]=1;col=1;row=7;}/*游戏结束*/void gameover(){int i,j;for(i=20;i>0;i--)for(j=1;j<15;j++)minbox(j*MINBOXSIZE,i*MINBOXSIZE,2,0);txt(103,203,"Game Over",3,10);}/*按键的设置*/void call_key(int keyx){switch(keyx){case VK_DOWN: { /*下方向键,横坐标加一。
C语⾔实现俄罗斯⽅块源代码本⽂实例为⼤家分享了C语⾔实现俄罗斯⽅块的具体代码,供⼤家参考,具体内容如下GitHub:Head.h#ifndef _HEAD_H_#define _HEAD_H_#include<graphics.h>#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<string.h>#define _CRT_SECURE_NO_WARNINGS 1//界⾯的相关的参数#define WALL_SQUARE_WIDTH 10 //围墙⽅块的宽度#define xWALL_SQUARE_NUM 30 //x轴⽅向的⽅块的数⽬#define yWALL_SQUARE_WIDTH 46 //y轴⽅向的⽅块的数⽬#define GAME_WALL_WIDTH (WALL_SQUARE_WIDTH*xWALL_SQUARE_NUM) //游戏区域的宽度 300#define GAME_WALL_HTGH (WALL_SQUARE_WIDTH*yWALL_SQUARE_WIDTH) //游戏区域的⾼度 460#define WINDOW_WIDTH 480 // 游戏总窗⼝宽度 480#define WINDOW_HIGH 460 // 游戏总窗⼝⾼度 460//定义俄罗斯⽅块的相关参数#define ROCK_SQUARE_WIDTH (2*WALL_SQUARE_WIDTH) //俄罗斯⽅块的⼤⼩是围墙的两倍 20#define xROCK_SQUARE_NUM ((GAME_WALL_WIDTH -20)/ROCK_SQUARE_WIDTH) // 游戏区x轴放的⽅块数⽬:14 #define yROCK_SQUARE_NUM ((GAME_WALL_HTGH -20)/ROCK_SQUARE_WIDTH) // 游戏区y轴放的⽅块数⽬:22 //定义移动⽅块的相关操作#define DIRECT_UP 3#define DIRECT_DOWN 2#define DIRECT_LEFT -1#define DIRECT_RIGHT 1/*数据结构-线性表(结构体数组)*/typedef struct ROCK{//⽤来表⽰⽅块的形状(每⼀个字节是8位,⽤每4位表⽰⽅块中的⼀⾏)unsigned short rockShapeBits;int nextRockIndex; //下⼀个⽅块,在数组中的下标} RockType;//⽅块在图形窗⼝中的位置(即定位4*4⼤块的左上⾓坐标)typedef struct LOCATE{int left;int top;} RockLocation_t;//全局变量-游戏板的状态描述(即表⽰当前界⾯哪些位置有⽅块)//0表⽰没有,1表⽰有(多加了两⾏和两列,形成⼀个围墙,便于判断⽅块是否能够移动)int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };int game_socres = 0; //全局分数// 把俄罗斯⽅块的19种类放到数组中int rockTypeNum = 19;RockType RockArray[19] = { (0, 0) };//预览区的⽅块的位置RockLocation_t preRockLocation = {GAME_WALL_WIDTH+70,70};//每次⽣成初始化⽅块的位置RockLocation_t initRockLocation = { (WALL_SQUARE_WIDTH + 100), WALL_SQUARE_WIDTH };//分数显⽰的位置//各个⽂件中的函数void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed);//初始化Init源⽂件void InitGame();//game.hvoid PlayGame();bool IsGameOver();#endifDraw.h#include"Head.h"//画出游戏界⾯void DrawGameWindow(){//先画出围墙setcolor(BLUE);setlinestyle(PS_SOLID,NULL,0);setfillcolor(BLUE);//画出上下围墙for (int x = WALL_SQUARE_WIDTH; x <= GAME_WALL_WIDTH; x += WALL_SQUARE_WIDTH){fillrectangle(x - WALL_SQUARE_WIDTH, 0, x, WALL_SQUARE_WIDTH); //上fillrectangle(x - WALL_SQUARE_WIDTH, GAME_WALL_HTGH - WALL_SQUARE_WIDTH, x, GAME_WALL_HTGH);//下 }//画出左右围墙for (int y = WALL_SQUARE_WIDTH; y <= GAME_WALL_HTGH; y += WALL_SQUARE_WIDTH){fillrectangle(0, y, WALL_SQUARE_WIDTH, y + WALL_SQUARE_WIDTH);//左fillrectangle(GAME_WALL_WIDTH - WALL_SQUARE_WIDTH, y, GAME_WALL_WIDTH, y + WALL_SQUARE_WIDTH);//右 }//画出右边统计分数及相关东西//画出分割线setcolor(WHITE);setlinestyle(PS_DASH,2);line(GAME_WALL_WIDTH + 20, 0, GAME_WALL_WIDTH + 20, GAME_WALL_HTGH);//设置字体LOGFONT font;gettextstyle(&font);settextstyle(18, 0, _T("宋体"));font.lfQuality = ANTIALIASED_QUALITY;//设置输出效果为抗锯齿//1显⽰预览形状outtextxy(GAME_WALL_WIDTH + 80, 30, _T("预览"));outtextxy(GAME_WALL_WIDTH + 80, 170, _T("分数"));outtextxy(GAME_WALL_WIDTH + 65, 250, _T("操作说明"));outtextxy(GAME_WALL_WIDTH + 40, 290, _T("w a s d控制⽅向"));outtextxy(GAME_WALL_WIDTH + 40, 335, _T("空格暂停"));//显⽰分数setcolor(RED);outtextxy(GAME_WALL_WIDTH + 90, 200, '0');}//在游戏区显⽰编号为rockIdx的⽅块void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed){int color;//⽅块的填充颜⾊int lineColor = WHITE;//线的颜⾊int boardFalg = 0;int xRock = 0;int yRock = 0;unsigned short rockCode = RockArray[rockIdx].rockShapeBits;//如果displayed为true的话,将⽅块块颜⾊设置为white,game_board对应的位置设置为1;//如果displayed为false的话,将⽅块块颜⾊设置为black,game_board对应的位置设置为0;displayed ? (color = RED, boardFalg = 1) : (color = BLACK,lineColor = BLACK, boardFalg = 0);setcolor(lineColor);setlinestyle(PS_SOLID);//设置为实线,xRock = LocatePtr->left;yRock = LocatePtr->top;int count = 0;//每4个换⾏,记录坐标偏移量unsigned short mask = 1;for (int i = 1; i <= 16; ++i){mask = 1 << (16 - i);if ((rockCode & mask) != 0) //如果不为0的话,就画出⼩⽅块{fillrectangle(xRock , yRock, xRock + ROCK_SQUARE_WIDTH, yRock + ROCK_SQUARE_WIDTH); }if (i % 4 == 0) //换⾏{yRock = yRock + ROCK_SQUARE_WIDTH;xRock = xRock = LocatePtr->left;}else{xRock += ROCK_SQUARE_WIDTH;}}}Init.h#include"Head.h"static void ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit);static void ReadRcok();void InitGame(){//把全局游戏游戏版初始化,边界初始化为1for (int i = 0; i < xROCK_SQUARE_NUM + 2; i++){game_board[0][i] = 1; //上边界game_board[yROCK_SQUARE_NUM + 1][i] = 1; //下边界}for (int i = 0; i < yROCK_SQUARE_NUM + 2; i++){game_board[i][0] = 1 ; //左边界game_board[i][xROCK_SQUARE_NUM + 1] = 1; //右边界}//读取俄罗斯⽅块ReadRcok();}//从⽂件中读取⽅块的形状存储到rockArray中void ReadRcok(){FILE* fp = fopen("RockShape.ini","r");if (NULL == fp){printf("打开⽂件失败\n");return;}unsigned char readBuf[1024]; //fp读取到字符串readbuf中unsigned short rockShapeBit = 0;//存放⽅块形状,占16⽐特位unsigned char rockShapeStr[16];//存放⽅块字符串int ShapeStrIdx = 0;int rockNum = 0;//统计⽅块的个数以及存放⽅块数组RockArray的下标int rocknext = 0;//⽅块数组中下⼀个形状int rockShapeStart = 0;//同⼀类型的形状while (true){size_t readSize = fread(readBuf, 1, 1024, fp);if (readSize == 0)break;//处理readbuffor (size_t idx = 0; idx < readSize; ++idx){//将字符存放到rockShapeStr中if (readBuf[idx] == '@' || readBuf[idx] == '#'){rockShapeStr[ShapeStrIdx] = (unsigned char)readBuf[idx];++ShapeStrIdx;}++idx; //可能idx == readSize了if (readBuf[idx] == '*')//修改上⼀次⽅块的next值{idx += 5;RockArray[--rockNum].nextRockIndex = rockShapeStart;rockNum++;rockShapeStart = rockNum;rocknext = rockShapeStart ;}}//可能没有填满if (ShapeStrIdx < 16){break;}else //填满shapestr{ShapeStrIdx = 0;//置0//将rockShapeStr 转为rockShapeBitShapeStrToBit(rockShapeStr, rockShapeBit);rocknext++;RockArray[rockNum].rockShapeBits = rockShapeBit;RockArray[rockNum].nextRockIndex = rocknext;rockNum++;}}}fclose(fp);}//将从⽂件中读取的字符串(长度默认为16)转换成 unsigned shortvoid ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit){rockShapeBit = 0;for (size_t idx = 0; idx < 16; ++idx){if (rockShapeStr[idx] == '@') //1{rockShapeBit |= (1 << (16 - idx - 1));}// #为0 不需要处理}}game.h#include"Head.h"#define _CRT_SECURE_NO_WARNINGS 1bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction);void SetGameBoardFlag(int rockIdx, RockLocation_t* curRockLocation);void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation); void FullLine();void UpdateSocres(int scores);void DelCurLine(int rowIdx);bool IsGameOver();void PlayGame(){char userHit = 0;//⽤户敲击键盘int curRockIndex = 0;//当前⽅块的rockArray下标int nextRockIndex = 0;//下次RockLocation_t curRockLocation;curRockLocation.left = initRockLocation.left;curRockLocation.top = initRockLocation.top;DWORD oldtime = 0;srand((unsigned int)time(NULL));curRockIndex = rand() % rockTypeNum;nextRockIndex = rand() % rockTypeNum;//画出预览区初始化⽅块//在初始位置和预览区显⽰⽅块形状bool moveAbled = false;while (true){//判断当前⽅块是否落地(判断能否再下移):如果落地,判断是否满⾏,再判断是否结束游戏,改变game_board ,画出下次初始化的⽅块,以及⽣成新的预览⽅块 //moveAbled = MoveAble(curRockIndex, &curRockLocation, DIRECT_DOWN);if (!moveAbled) //判断是否落地,不能下移表⽰落地{//修改game_board的值SetGameBoardFlag(curRockIndex, &curRockLocation);FullLine();if (IsGameOver()){MessageBox(NULL, _T("游戏结束"), _T("GAME OVER"), MB_OK);exit(0);}//为下次⽣成模块开始准备DisplayRock(nextRockIndex, &preRockLocation, false);//擦除旧的⽅块curRockIndex = nextRockIndex;nextRockIndex = rand() % rockTypeNum; //⽣成新的预览⽅块DisplayRock(curRockIndex, &initRockLocation, 1);DisplayRock(nextRockIndex, &preRockLocation, 1);FlushBatchDraw();//修改curRockLocation的值curRockLocation.left = initRockLocation.left;curRockLocation.top = initRockLocation.top;}if (kbhit()) //如果敲击键盘了就处理按键{userHit = getch();UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation);}//没有就⾃动下移⼀个单位 :不能⽤else,因为可能按键不是上下左右DWORD newtime = GetTickCount();if (newtime - oldtime >= (unsigned int)(300) && moveAbled == TRUE){oldtime = newtime;DisplayRock(curRockIndex, &curRockLocation, false);curRockLocation.top += ROCK_SQUARE_WIDTH; //下落⼀格}//AutomaticDownMove(curRockIndex, &curRockLocation);//画出新⽅块DisplayRock(curRockIndex, &curRockLocation, 1);FlushBatchDraw();Sleep(20);}}//响应键盘命令时间void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation){switch (userHit){case 'W':case 'w'://↑if (MoveAble(RockArray[*RockIndex].nextRockIndex, curRockLocation, DIRECT_UP)){DisplayRock(*RockIndex, curRockLocation, false);*RockIndex = RockArray[*RockIndex].nextRockIndex;}break;case 'S':case 's'://↓if (MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN)){DisplayRock(*RockIndex, curRockLocation, false);curRockLocation->top += 2 * (ROCK_SQUARE_WIDTH);if (!MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN)){curRockLocation->top -= ROCK_SQUARE_WIDTH;}}break;case 'A':if (MoveAble(*RockIndex, curRockLocation, DIRECT_LEFT)){DisplayRock(*RockIndex, curRockLocation, false);curRockLocation->left -= ROCK_SQUARE_WIDTH;}break;case 'D':case 'd': //→if (MoveAble(*RockIndex, curRockLocation, DIRECT_RIGHT)){DisplayRock(*RockIndex, curRockLocation, FALSE);curRockLocation->left += ROCK_SQUARE_WIDTH;}break;case ' ': //暂停while (1){userHit = getch();if (userHit == ' ')break;}break;default:break;}}//判断是否满⾏,满⾏消除,然后计算得分void FullLine(){bool linefull = true;int idx = yROCK_SQUARE_NUM;//从最后⼀⾏往上查找 22int count = 0;while (count != xROCK_SQUARE_NUM ) //遇到空⾏ 14{linefull = true;count = 0;for (int i = 1; i <= xROCK_SQUARE_NUM; ++i){if (game_board[idx][i] == 0){linefull = false;count++;}}if (linefull) //满⾏,消除当前⾏,更新分数{DelCurLine(idx);game_socres += 3;UpdateSocres(game_socres);idx++;//因为下⾯要减1}idx--;}}void UpdateSocres(int scores){setcolor(RED);TCHAR s[10];_stprintf(s, _T("%d"), scores);outtextxy(GAME_WALL_WIDTH + 90, 200, s);}//消除当前⾏void DelCurLine(int rowIdx){//擦除当前⾏setcolor(BLACK);setfillcolor(BLACK);for (int i = 1; i < xROCK_SQUARE_NUM; ++i){fillrectangle(WALL_SQUARE_WIDTH + (i - 1)*ROCK_SQUARE_WIDTH, (rowIdx - 1)*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH, WALL_SQUARE_WIDTH + i*ROCK_SQUARE_WIDTH, rowIdx*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH);}//把上⾯的向下移int cnt = 0;while (cnt != xROCK_SQUARE_NUM) //直到遇到是空⾏的为⽌cnt = 0;for (int i = 1; i <= xROCK_SQUARE_NUM; i++){game_board[rowIdx][i] = game_board[rowIdx - 1][i];//擦除上⾯的⼀⾏setcolor(BLACK);setfillcolor(BLACK);fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1) - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1));//显⽰下⾯的⼀⾏if (game_board[rowIdx][i] == 1){setcolor(WHITE);setfillcolor(RED);fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx - ROCK_SQUARE_WIDTH ,WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx);}if (game_board[rowIdx][i] == 0)cnt++; //统计⼀⾏是不是都是空格}//forrowIdx--;}}//是否可以移动⽅块bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction){int mask;int rockX;int rockY;rockX = currentLocatePtr->left;rockY = currentLocatePtr->top;mask = (unsigned short)1 << 15;for (int i = 1; i <= 16; i++){//与掩码相与为1的即为⽅块上的点if ((RockArray[rockIndex].rockShapeBits & mask) != 0){//判断能否移动(即扫描即将移动的位置是否与设置的围墙有重叠)//若是向上(即翻滚变形)if (f_direction == DIRECT_UP){//因为此情况下传⼊的是下⼀个⽅块的形状,故我们直接判断此⽅块的位置是否已经被占//判断下⼀个⽅块if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1][(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1)return false;}//如果是向下⽅向移动else if (f_direction == DIRECT_DOWN){if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 2][(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1)return false;}else //如果是左右⽅向移动{ //f_direction的DIRECT_LEFT为-1,DIRECT_RIGHT为1,故直接加f_direction即可判断。