效果截图:
my-tetris.c
#include <stdio.h>
#include <windows.h>
#include <time.h>
//常量定义区
#define M_X 100//定义地图的最大宽度
#define M_Y 100//定义地图的最大高度
//全局变量定义区
int i,j;//for循环专用变量
int m[M_X][M_Y];//定义最大地图数组
int X;//使用宽度
int Y;//使用高度
int Wx;//方块头实时位置
int Wy;//方块头实时位置
int Ox;//方块头实时上一次位置
int Oy;//方块头实时上一次位置
int R[4][2];//方块体实时位置
int T;//方块体实时颜色
int E,C;//方块体实时形状
int ch;//按键信息
int Z;//碰撞标志
int F;//得分
int J;//是否开启数据记录
clock_t s_t_1, s_t_2;
#include "my-tetris-3.h"
#include "my-tetris-2.h"
#include "my-tetris-1.h"
//程序运行函数
int run(){
set_cursor(0);//设置光标,flg=1:显示光标 flg=0:隐藏光标
hollo();//介绍
f_sz_m();//地图数组初始化
f_R();//初始化R数组
f_d();//初始化data
f_bl();//变量初始化
s_gk();//设置使用高度和宽度
s_j();//设置是否开启数据记录
r_gk();//将高度和宽度写入地图
r_d();//将地图记录进data
d_m();//打印地图
s_m();//游戏说明
int a=1;
srand((unsigned)time(NULL ));// 设置随机种子
while(1){
if(f_d_fx()){return 1;}//方块起始开始
while(1){
change(2);//更改
s_t_1=clock();//计时
while(1){
set_cocate(0,Y);
set_color(15,0);
printf(" ");
ch=0;
if(kbhit()){
switch(ch=getch()){//获取用户按下的按键
case 0xE0:switch(ch=getch()){//分析按键
case 72:change(1);break;
case 80:change(2);break;
case 75:change(3);break;
case 77:change(4);break;
default:break;
}
break;
case 32:command(2);break;
default:break;
}
}
s_t_2=clock();//计时
if(s_t_2-s_t_1>1000-F/2){change(2);s_t_1=clock();}
if(Z){break;}
}
if(Z){break;}
}
c_h();//检测是否成行
}
return 0;
}
void main(){
int a;
while(1){
if(run()){
command(2);
command(1);
printf("游戏结束\n");
printf("重新开始请按1,结束请按0\n");
if(input_int(0,1)!=1){break;}
}
}
}
my-tetris-1.h
//程序运行主文件
//将地图记录进data
void r_d(){
if(J){
FILE *fp;
int i,j;
fp=fopen("data.txt","a");
for(i=0;i<X;i++){
fprintf(fp,"|");
for(j=0;j<Y;j++){
fprintf(fp,"%3d|",m[i][j]);
}
fprintf(fp,"\n");
}
fprintf(fp,"\n");
fclose(fp);
}
}
//设置是否开启数据记录
void s_j(){
printf("是否开启数据记录 0=否 1=是 \n");
J=input_int(0,1);
}
//设置使用高度和宽度
void s_gk(){
printf("宽度设置,建议20 ");
X=input_int(10,100);
printf("高度设置,建议20 ");
Y=input_int(15,100);
}
//将高度和宽度写入地图
void r_gk(){
for(i=0;i<X;i++){
for(j=0;j<Y;j++){
if(i==0||i==X-1||j==Y-1){
m[i][j]=20;
}
}
}
}
//打印地图
void d_m(){
command(1);
set_color(15,0);
for(i=0;i<X;i++){
for(j=0;j<Y;j++){
if(m[i][j]==20){
set_cocate(i,j);
printf("■");
}
}
}
}
//设置R数组
void s_R(int a,int b,int c,int d,int e,int f,int g,int h){
R[0][0]=a;R[0][1]=b;
R[1][0]=c;R[1][1]=d;
R[2][0]=e;R[2][1]=f;
R[3][0]=g;R[3][1]=h;
}
//设置W
void s_W(int a,int b){
Ox=Wx;Oy=Wy;
if(a<1){a=1;}
if(E==1){if(a>X-5){a=X-5;}}
if(E==2){if(a>X-2){a=X-2;}}
if(E==3||E==5||E==7||E==9||E==11||E==13||E==15||E==17){if(a>X-4){a=X-4;}}
if(E==4||E==6||E==8||E==10||E==12||E==14||E==16||E==18||E==19){if(a>X-3){a=X-3;}}
Wx=a;Wy=b;
}
//方块设置
/*
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| ■■■■| ■□□□| ■□□□| ■■□□| ■■■□| □■□□| □□■□| ■□□□| ■■■□| ■■□□|
| □□□□| ■□□□| ■■■□| ■□□□| □□■□| □■□□| ■■■□| ■□□□| ■□□□| □■□□|
| □□□□| ■□□□| □□□□| ■□□□| □□□□| ■■□□| □□□□| ■■□□| □□□□| □■□□|
| □□□□| ■□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□|
| 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| □■□□| ■□□□| ■■■□| □■□□| ■■□□| □■□□| □■■□| ■□□□| ■■□□| □□□□|
| ■■■□| ■■□□| □■□□| ■■□□| □■■□| ■■□□| ■■□□| ■■□□| ■■□□| □□□□|
| □□□□| ■□□□| □□□□| □■□□| □□□□| ■□□□| □□□□| □■□□| □□□□| □□□□|
| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□| □□□□|
Wx,Wy Wx+1,Wy Wx+2,Wy Wx+3,Wy
Wx,Wy+1 Wx+1,Wy+1 Wx+2,Wy+1 Wx+3,Wy+1
Wx,Wy+2 Wx+1,Wy+2 Wx+2,Wy+2 Wx+3,Wy+2
Wx,Wy+3 Wx+1,Wy+3 Wx+2,Wy+3 Wx+3,Wy+3
*/
void s_fk(int a){
switch(a){
case 1 :s_R(Wx,Wy, Wx+1,Wy, Wx+2,Wy, Wx+3,Wy );break;
case 2 :s_R(Wx,Wy, Wx,Wy+1, Wx,Wy+2, Wx,Wy+3 );break;
case 3 :s_R(Wx,Wy, Wx,Wy+1, Wx+1,Wy+1,Wx+2,Wy+1);break;
case 4 :s_R(Wx,Wy, Wx+1,Wy, Wx,Wy+1, Wx,Wy+2 );break;
case 5 :s_R(Wx,Wy, Wx+1,Wy, Wx+2,Wy, Wx+2,Wy+1);break;
case 6 :s_R(Wx+1,Wy,Wx+1,Wy+1,Wx,Wy+2, Wx+1,Wy+2);break;
case 7 :s_R(Wx+2,Wy,Wx,Wy+1, Wx+1,Wy+1,Wx+2,Wy+1);break;
case 8 :s_R(Wx,Wy, Wx,Wy+1, Wx,Wy+2, Wx+1,Wy+2);break;
case 9 :s_R(Wx,Wy, Wx+1,Wy, Wx+2,Wy, Wx,Wy+1 );break;
case 10:s_R(Wx,Wy, Wx+1,Wy, Wx+1,Wy+1,Wx+1,Wy+2);break;
case 11:s_R(Wx+1,Wy,Wx,Wy+1, Wx+1,Wy+1,Wx+2,Wy+1);break;
case 12:s_R(Wx,Wy, Wx,Wy+1, Wx+1,Wy+1,Wx,Wy+2 );break;
case 13:s_R(Wx,Wy, Wx+1,Wy, Wx+2,Wy, Wx+1,Wy+1);break;
case 14:s_R(Wx+1,Wy,Wx,Wy+1, Wx+1,Wy+1,Wx+1,Wy+2);break;
case 15:s_R(Wx,Wy, Wx+1,Wy, Wx+1,Wy+1,Wx+2,Wy+1);break;
case 16:s_R(Wx+1,Wy,Wx,Wy+1, Wx+1,Wy+1,Wx,Wy+2 );break;
case 17:s_R(Wx+1,Wy,Wx+2,Wy, Wx,Wy+1, Wx+1,Wy+1);break;
case 18:s_R(Wx,Wy, Wx,Wy+1, Wx+1,Wy+1,Wx+1,Wy+2);break;
case 19:s_R(Wx,Wy, Wx+1,Wy, Wx,Wy+1, Wx+1,Wy+1);break;
default:break;
}
}
//将方块位置记录进地图
void r_fk_t_m(int a){
for(i=0;i<4;i++){
if(a){m[R[i][0]][R[i][1]]=E;}
else{m[R[i][0]][R[i][1]]=0;}
}
}
//显示方块 1=显示 0清除
void d_fk(int a){
if(a){
if(E==1||E==2){set_color(8,0);}
if(E==3||E==4||E==5||E==6){set_color(9,0);}
if(E==7||E==8||E==9||E==10){set_color(10,0);}
if(E==11||E==12||E==13||E==14){set_color(11,0);}
if(E==15||E==16){set_color(12,0);}
if(E==17||E==18){set_color(13,0);}
if(E==19){set_color(14,0);}
}
else{
set_color(0,0);
}
r_fk_t_m(a);//将方块位置记录进地图
for(i=0;i<4;i++){
set_cocate(R[i][0],R[i][1]);
printf("■");
}
}
//方块起始开始
int f_d_fx(){
Z=0;
E=C;//方块形状设置
Wx=X+1;Wy=5; //设置位置
s_fk(C);//方块设置
d_fk(0);//显示方块
C=0;
while(!C){C=rand()%20;}//方块形状设置
Wx=X+1;Wy=5; //设置位置
s_fk(C);//方块设置
if(C==1||C==2){set_color(8,0);}
if(C==3||C==4||C==5||C==6){set_color(9,0);}
if(C==7||C==8||C==9||C==10){set_color(10,0);}
if(C==11||C==12||C==13||C==14){set_color(11,0);}
if(C==15||C==16){set_color(12,0);}
if(C==17||C==18){set_color(13,0);}
if(C==19){set_color(14,0);}
for(i=0;i<4;i++){
set_cocate(R[i][0],R[i][1]);
printf("■");
}
set_cocate(X+1,4);
set_color(15,0);
printf("下一个方块");
s_W(X/2-2,0);//设置起始位置
s_fk(E);//方块设置
if(c_pz()){return 1;}
d_fk(1);//显示方块
r_d();//将地图记录进data
usleep(100000);
d_fk(0);//显示方块
return 0;
}
//碰撞检测
int c_pz(){
for(i=0;i<4;i++){
if(m[R[i][0]][R[i][1]]!=0){return 1;}
}
return 0;
}
//方块旋转
void chang1(){
switch(E){
case 1 :E=2;break;
case 2 :E=1;break;
case 3 :E=4;break;
case 4 :E=5;break;
case 5 :E=6;break;
case 6 :E=3;break;
case 7 :E=8;break;
case 8 :E=9;break;
case 9 :E=10;break;
case 10:E=7;break;
case 11:E=12;break;
case 12:E=13;break;
case 13:E=14;break;
case 14:E=11;break;
case 15:E=16;break;
case 16:E=15;break;
case 17:E=18;break;
case 18:E=17;break;
case 19:E=19;break;
default:break;
}
}
//方块旋转
void chang2(){
switch(E){
case 2 :E=1;break;
case 1 :E=2;break;
case 4 :E=2;break;
case 5 :E=4;break;
case 6 :E=5;break;
case 3 :E=6;break;
case 8 :E=7;break;
case 9 :E=8;break;
case 10:E=9;break;
case 7:E=10;break;
case 12:E=11;break;
case 13:E=12;break;
case 14:E=13;break;
case 11:E=14;break;
case 16:E=15;break;
case 15:E=16;break;
case 18:E=17;break;
case 17:E=18;break;
case 19:E=19;break;
default:break;
}
}
//更改
void change(int a){
d_fk(0);//显示方块
switch(a){
case 1 :chang1();break;
case 2 :s_W(Wx,Wy+1);break;
case 3 :s_W(Wx-1,Wy);break;
case 4 :s_W(Wx+1,Wy);break;
default:break;
}
s_fk(E);//方块设置
if(c_pz()){//碰撞检测
if(a==2){
Z=1;//碰撞标志
}
if(a==1){
chang2();
s_W(Wx,Wy);//设置位置
s_fk(E);//方块设置
}
else{
s_W(Ox,Oy);//设置位置
s_fk(E);//方块设置
}
}
d_fk(1);//显示方块
r_d();//将地图记录进data
}
//检测是否成行
void c_h(){
int a;
int k;
for(j=1;j<Y-1;j++){
a=0;
for(i=1;i<X-1;i++){
if(m[i][j]!=0){
a++;
}
}
if(a==X-2){
for(k=j;k>1;k--){
for(i=1;i<X-1;i++){
m[i][k]=0;
m[i][k]=m[i][k-1];
if(m[i][k]==1||m[i][k]==2){set_color(8,0);}
if(m[i][k]==3||m[i][k]==4||m[i][k]==5||m[i][k]==6){set_color(9,0);}
if(m[i][k]==7||m[i][k]==8||m[i][k]==9||m[i][k]==10){set_color(10,0);}
if(m[i][k]==11||m[i][k]==12||m[i][k]==13||m[i][k]==14){set_color(11,0);}
if(m[i][k]==15||m[i][k]==16){set_color(12,0);}
if(m[i][k]==17||m[i][k]==18){set_color(13,0);}
if(m[i][k]==19){set_color(14,0);}
if(m[i][k]==0){set_color(0,0);}
set_cocate(i,k);
printf("■");
}
}
F+=X-2;
set_cocate(X+1,2);
set_color(12,0);
printf("分数:%4d",F);
set_cocate(X+1,3);
set_color(14,0);
printf("速度:%4d",1000-F/2);
}
}
}
//介绍
void hollo(){
set_color(12,0);
printf("########################################\n");
printf("#Created At:20170906 #\n");
printf("#Algorithm Gossip:tetris #\n");
printf("#Developer:wunanhui #\n");
printf("#Referenced By:http://www.wunanhui.wang#\n");
printf("########################################\n");
set_color(15,0);
printf("游戏规则\n");
printf("由小方块组成的不同形状的板块陆续从屏幕上\n");
printf("方落下来,玩家通过调整板块的位置和方向,\n");
printf("使它们在屏幕底部拼出完整的一条或几条。这\n");
printf("些完整的横条会随即消失,给新落下来的板块\n");
printf("腾出空间,与此同时,玩家得到分数奖励。没\n");
printf("有被消除掉的方块不断堆积起来,一旦堆到屏\n");
printf("幕顶端,玩家便告输,游戏结束。\n");
printf("\n");
}
//游戏说明
void s_m(){
set_color(15,0);
set_cocate(X+1,0);
printf("Designer:wnh");
set_cocate(X+1,9);
printf("游戏说明");
set_cocate(X+1,10);
printf("↑:旋转");
set_cocate(X+1,11);
printf("←:左移");
set_cocate(X+1,12);
printf("→:右移");
set_cocate(X+1,13);
printf("↓:下移");
set_cocate(X+1,14);
printf("空格:暂停");
set_cocate(X+1,2);
set_color(12,0);
printf("分数:%4d",F);
set_cocate(X+1,3);
set_color(14,0);
printf("速度:%4d",1000-F/2);
}
my-tetris-2.h
//变量初始化头文件
//变量初始化
void f_bl(){
X=0;//使用宽度
Y=0;//使用高度
Wx=0;//方块头实时位置
Wy=0;//方块头实时位置
T=0;//方块体实时颜色
E=0;//方块体实时形状
Ox=0;//方块头实时上一次位置
Oy=0;//方块头实时上一次位置
Z=0;//碰撞标志
s_t_1=s_t_2=0;
F=0;
C=1;
J=0;
}
//地图数组初始化
void f_sz_m(){
for(i=0;i<M_X;i++){
for(j=0;j<M_Y;j++){
m[i][j]=0;
}
}
}
//初始化R数组
void f_R(){
for(i=0;i<4;i++){
for(j=0;j<2;j++){
R[i][j]=0;
}
}
}
//初始化data
void f_d(){
FILE *fp;
fp=fopen("data.txt","w");
fclose(fp);
}
my-tetris-3.h
//基础函数头文件
/*
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 10 = 淡绿色
3 = 浅绿色 11 = 淡浅绿色
4 = 红色 12 = 淡红色
5 = 紫色 13 = 淡紫色
6 = 黄色 14 = 淡黄色
7 = 白色 15 = 亮白色
*/
//设置字符前景色和底色,ForeColor:字色,BackColor:背景色,基本颜色0-7,8-15是亮度加强的基本色
void set_color(int ForeColor,int BackColor){
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
SetConsoleTextAttribute(hConsole,BackColor*16+ForeColor) ;
}
//设置光标,flg=1:显示光标 flg=0:隐藏光标
void set_cursor(int flg){
HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursor_info={100,flg};
SetConsoleCursorInfo(hOut,&cursor_info);
}
//设置字符显示位置
void set_cocate(int x,int y)
{
x*=2;//增加
HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
COORD loc={x,y};
SetConsoleCursorPosition(hOut,loc);
}
//执行系统命令
void command(int a){
/*
1 = 清屏
2 = 暂停
*/
switch(a){
case 1:system("cls");break;
case 2:set_cocate(0,Y);set_color(15,0);system("pause");break;
default:break;
}
}
//整形数据输入
int input_int(int i,int j){
int a=-100,k=0;
printf("请输入 %d~%d 的数值,并按回车确定;\n",i,j);
while(a>j||a<i){
if(k!=0){
printf("输入错误,请重新输入 %d~%d 的数值,并按回车确定;\n",i,j);
}
scanf("%d",&a);
k++;
}
return a;
}